aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/gtk-vlc-player/gtk-vlc-player.c261
-rw-r--r--lib/gtk-vlc-player/gtk-vlc-player.h17
2 files changed, 166 insertions, 112 deletions
diff --git a/lib/gtk-vlc-player/gtk-vlc-player.c b/lib/gtk-vlc-player/gtk-vlc-player.c
index 7e7832b..d3caed4 100644
--- a/lib/gtk-vlc-player/gtk-vlc-player.c
+++ b/lib/gtk-vlc-player/gtk-vlc-player.c
@@ -18,6 +18,9 @@
static void gtk_vlc_player_class_init(GtkVlcPlayerClass *klass);
static void gtk_vlc_player_init(GtkVlcPlayer *klass);
+static void gtk_vlc_player_dispose(GObject *gobject);
+static void gtk_vlc_player_finalize(GObject *gobject);
+
static void widget_on_realize(GtkWidget *widget, gpointer data);
static gboolean widget_on_click(GtkWidget *widget, GdkEventButton *event, gpointer data);
@@ -32,43 +35,54 @@ static void vlc_length_changed(const struct libvlc_event_t *event, void *userdat
static void vlc_player_load_media(GtkVlcPlayer *player, libvlc_media_t *media);
+/** @private */
+#define GOBJECT_UNREF_SAFE(VAR) do { \
+ if ((VAR) != NULL) { \
+ g_object_unref(VAR); \
+ VAR = NULL; \
+ } \
+} while (0)
+
+/** @private */
+#define GTK_VLC_PLAYER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GTK_TYPE_VLC_PLAYER, GtkVlcPlayerPrivate))
+
+/** @private */
+struct _GtkVlcPlayerPrivate {
+ GtkObject *time_adjustment;
+ gulong time_adj_on_value_changed_id;
+
+ GtkObject *volume_adjustment;
+ gulong vol_adj_on_value_changed_id;
+
+ libvlc_instance_t *vlc_inst;
+ libvlc_media_player_t *media_player;
+
+ gboolean isFullscreen;
+ GtkWidget *fullscreen_window;
+};
+
enum {
TIME_CHANGED_SIGNAL,
LENGTH_CHANGED_SIGNAL,
LAST_SIGNAL
};
-
static guint gtk_vlc_player_signals[LAST_SIGNAL] = {0, 0};
-GType
-gtk_vlc_player_get_type(void)
-{
- static GType type = 0;
-
- if (!type) {
- /* FIXME: destructor needed */
- const GTypeInfo info = {
- sizeof(GtkVlcPlayerClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc)gtk_vlc_player_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof(GtkVlcPlayer),
- 0, /* n_preallocs */
- (GInstanceInitFunc)gtk_vlc_player_init,
- };
-
- type = g_type_register_static(GTK_TYPE_ALIGNMENT,
- "GtkVlcPlayer", &info, 0);
- }
-
- return type;
-}
+/**
+ * @private
+ * will create gtk_vlc_player_get_type and set gtk_vlc_player_parent_class
+ */
+G_DEFINE_TYPE(GtkVlcPlayer, gtk_vlc_player, GTK_TYPE_ALIGNMENT);
static void
gtk_vlc_player_class_init(GtkVlcPlayerClass *klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->dispose = gtk_vlc_player_dispose;
+ gobject_class->finalize = gtk_vlc_player_finalize;
+
gtk_vlc_player_signals[TIME_CHANGED_SIGNAL] =
g_signal_new("time-changed",
G_TYPE_FROM_CLASS(klass),
@@ -86,6 +100,8 @@ gtk_vlc_player_class_init(GtkVlcPlayerClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__LONG, G_TYPE_NONE,
1, G_TYPE_INT64);
+
+ g_type_class_add_private(klass, sizeof(GtkVlcPlayerPrivate));
}
static void
@@ -95,12 +111,11 @@ gtk_vlc_player_init(GtkVlcPlayer *klass)
GdkColor color;
libvlc_event_manager_t *evman;
+ klass->priv = GTK_VLC_PLAYER_GET_PRIVATE(klass);
gtk_alignment_set(GTK_ALIGNMENT(klass), 0., 0., 1., 1.);
drawing_area = gtk_drawing_area_new();
- gtk_container_add(GTK_CONTAINER(klass), drawing_area);
- gtk_widget_show(drawing_area);
-
+ /** @bug use styles */
gdk_color_parse("black", &color);
gtk_widget_modify_bg(drawing_area, GTK_STATE_NORMAL, &color);
@@ -111,31 +126,75 @@ gtk_vlc_player_init(GtkVlcPlayer *klass)
g_signal_connect(G_OBJECT(drawing_area), "button-press-event",
G_CALLBACK(widget_on_click), klass);
- klass->time_adjustment = gtk_adjustment_new(0., 0., 0.,
- GTK_VLC_PLAYER_ADJ_STEP,
- GTK_VLC_PLAYER_ADJ_PAGE, 0.);
- klass->time_adj_on_value_changed_id =
- g_signal_connect(G_OBJECT(klass->time_adjustment), "value-changed",
+ gtk_container_add(GTK_CONTAINER(klass), drawing_area);
+ gtk_widget_show(drawing_area);
+ /*
+ * drawing area will be destroyed automatically with the
+ * GtkContainer/GtkVlcPlayer
+ * (it is derived from GtkObject and has one reference after adding it
+ * to the container).
+ */
+
+ klass->priv->time_adjustment = gtk_adjustment_new(0., 0., 0.,
+ GTK_VLC_PLAYER_ADJ_STEP,
+ GTK_VLC_PLAYER_ADJ_PAGE, 0.);
+ g_object_ref_sink(klass->priv->time_adjustment);
+ klass->priv->time_adj_on_value_changed_id =
+ g_signal_connect(G_OBJECT(klass->priv->time_adjustment),
+ "value-changed",
G_CALLBACK(time_adj_on_value_changed), klass);
- klass->volume_adjustment = gtk_adjustment_new(1., 0., 1., 0.02, 0., 0.);
- klass->vol_adj_on_value_changed_id =
- g_signal_connect(G_OBJECT(klass->volume_adjustment), "value-changed",
+ klass->priv->volume_adjustment = gtk_adjustment_new(1., 0., 1.,
+ 0.02, 0., 0.);
+ g_object_ref_sink(klass->priv->volume_adjustment);
+ klass->priv->vol_adj_on_value_changed_id =
+ g_signal_connect(G_OBJECT(klass->priv->volume_adjustment),
+ "value-changed",
G_CALLBACK(vol_adj_on_value_changed), klass);
- klass->vlc_inst = libvlc_new(0, NULL);
- klass->media_player = libvlc_media_player_new(klass->vlc_inst);
+ klass->priv->vlc_inst = libvlc_new(0, NULL);
+ klass->priv->media_player = libvlc_media_player_new(klass->priv->vlc_inst);
/* sign up for time updates */
- evman = libvlc_media_player_event_manager(klass->media_player);
+ evman = libvlc_media_player_event_manager(klass->priv->media_player);
libvlc_event_attach(evman, libvlc_MediaPlayerTimeChanged,
vlc_time_changed, klass);
libvlc_event_attach(evman, libvlc_MediaPlayerLengthChanged,
vlc_length_changed, klass);
- klass->isFullscreen = FALSE;
- klass->fullscreen_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ klass->priv->isFullscreen = FALSE;
+ klass->priv->fullscreen_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ g_object_ref_sink(klass->priv->fullscreen_window);
+}
+
+static void
+gtk_vlc_player_dispose(GObject *gobject)
+{
+ GtkVlcPlayer *player = GTK_VLC_PLAYER(gobject);
+
+ /*
+ * destroy might be called more than once, but we have only one
+ * reference for each object
+ */
+ GOBJECT_UNREF_SAFE(player->priv->time_adjustment);
+ GOBJECT_UNREF_SAFE(player->priv->volume_adjustment);
+ GOBJECT_UNREF_SAFE(player->priv->fullscreen_window);
+
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS(gtk_vlc_player_parent_class)->dispose(gobject);
+}
+
+static void
+gtk_vlc_player_finalize(GObject *gobject)
+{
+ GtkVlcPlayer *player = GTK_VLC_PLAYER(gobject);
+
+ libvlc_media_player_release(player->priv->media_player);
+ libvlc_release(player->priv->vlc_inst);
+
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS(gtk_vlc_player_parent_class)->finalize(gobject);
}
static void
@@ -145,9 +204,11 @@ widget_on_realize(GtkWidget *widget, gpointer user_data)
GdkWindow *window = gtk_widget_get_window(widget);
#ifdef __WIN32__
- libvlc_media_player_set_hwnd(player->media_player, GDK_WINDOW_HWND(window));
+ libvlc_media_player_set_hwnd(player->priv->media_player,
+ GDK_WINDOW_HWND(window));
#else
- libvlc_media_player_set_xwindow(player->media_player, GDK_WINDOW_XID(window));
+ libvlc_media_player_set_xwindow(player->priv->media_player,
+ GDK_WINDOW_XID(window));
#endif
}
@@ -159,22 +220,20 @@ widget_on_click(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
if (event->type != GDK_2BUTTON_PRESS || event->button != 1)
return TRUE;
- //DEBUG("player_widget double-click");
-
- if (player->isFullscreen) {
+ if (player->priv->isFullscreen) {
gtk_widget_reparent(widget, GTK_WIDGET(player));
gtk_widget_show(widget);
- gtk_widget_hide(player->fullscreen_window);
- gtk_window_unfullscreen(GTK_WINDOW(player->fullscreen_window));
+ gtk_widget_hide(player->priv->fullscreen_window);
+ gtk_window_unfullscreen(GTK_WINDOW(player->priv->fullscreen_window));
- player->isFullscreen = FALSE;
+ player->priv->isFullscreen = FALSE;
} else {
- gtk_window_fullscreen(GTK_WINDOW(player->fullscreen_window));
- gtk_widget_show(player->fullscreen_window);
- gtk_widget_reparent(widget, player->fullscreen_window);
+ gtk_window_fullscreen(GTK_WINDOW(player->priv->fullscreen_window));
+ gtk_widget_show(player->priv->fullscreen_window);
+ gtk_widget_reparent(widget, player->priv->fullscreen_window);
gtk_widget_show(widget);
- player->isFullscreen = TRUE;
+ player->priv->isFullscreen = TRUE;
}
return TRUE;
@@ -201,12 +260,12 @@ update_time(GtkVlcPlayer *player, gint64 new_time)
new_time);
/* ensure that time_adj_on_value_changed() will not be executed */
- g_signal_handler_block(G_OBJECT(player->time_adjustment),
- player->time_adj_on_value_changed_id);
- gtk_adjustment_set_value(GTK_ADJUSTMENT(player->time_adjustment),
+ g_signal_handler_block(G_OBJECT(player->priv->time_adjustment),
+ player->priv->time_adj_on_value_changed_id);
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(player->priv->time_adjustment),
(gdouble)new_time);
- g_signal_handler_unblock(G_OBJECT(player->time_adjustment),
- player->time_adj_on_value_changed_id);
+ g_signal_handler_unblock(G_OBJECT(player->priv->time_adjustment),
+ player->priv->time_adj_on_value_changed_id);
}
static inline void
@@ -215,18 +274,16 @@ update_length(GtkVlcPlayer *player, gint64 new_length)
g_signal_emit(player, gtk_vlc_player_signals[LENGTH_CHANGED_SIGNAL], 0,
new_length);
- gtk_adjustment_set_upper(GTK_ADJUSTMENT(player->time_adjustment),
+ gtk_adjustment_set_upper(GTK_ADJUSTMENT(player->priv->time_adjustment),
(gdouble)new_length);
}
-/*
- * VLC callbacks are invoked from another thread!
- */
static void
vlc_time_changed(const struct libvlc_event_t *event, void *user_data)
{
assert(event->type == libvlc_MediaPlayerTimeChanged);
+ /* VLC callbacks are invoked from another thread! */
gdk_threads_enter();
update_time(GTK_VLC_PLAYER(user_data),
(gint64)event->u.media_player_time_changed.new_time);
@@ -238,39 +295,41 @@ vlc_length_changed(const struct libvlc_event_t *event, void *user_data)
{
assert(event->type == libvlc_MediaPlayerLengthChanged);
+ /* VLC callbacks are invoked from another thread! */
gdk_threads_enter();
update_length(GTK_VLC_PLAYER(user_data),
(gint64)event->u.media_player_length_changed.new_length);
gdk_threads_leave();
}
-/*
- * API
- */
-
-GtkWidget *
-gtk_vlc_player_new(void)
-{
- return GTK_WIDGET(g_object_new(GTK_TYPE_VLC_PLAYER, NULL));
-}
-
static void
vlc_player_load_media(GtkVlcPlayer *player, libvlc_media_t *media)
{
libvlc_media_parse(media);
- libvlc_media_player_set_media(player->media_player, media);
+ libvlc_media_player_set_media(player->priv->media_player, media);
/* NOTE: media was parsed so get_duration works */
update_length(player, (gint64)libvlc_media_get_duration(media));
update_time(player, 0);
}
+/*
+ * API
+ */
+
+GtkWidget *
+gtk_vlc_player_new(void)
+{
+ return GTK_WIDGET(g_object_new(GTK_TYPE_VLC_PLAYER, NULL));
+}
+
gboolean
gtk_vlc_player_load_filename(GtkVlcPlayer *player, const gchar *file)
{
libvlc_media_t *media;
- media = libvlc_media_new_path(player->vlc_inst, (const char *)file);
+ media = libvlc_media_new_path(player->priv->vlc_inst,
+ (const char *)file);
if (media == NULL)
return TRUE;
vlc_player_load_media(player, media);
@@ -284,7 +343,8 @@ gtk_vlc_player_load_uri(GtkVlcPlayer *player, const gchar *uri)
{
libvlc_media_t *media;
- media = libvlc_media_new_location(player->vlc_inst, (const char *)uri);
+ media = libvlc_media_new_location(player->priv->vlc_inst,
+ (const char *)uri);
if (media == NULL)
return TRUE;
vlc_player_load_media(player, media);
@@ -296,31 +356,31 @@ gtk_vlc_player_load_uri(GtkVlcPlayer *player, const gchar *uri)
void
gtk_vlc_player_play(GtkVlcPlayer *player)
{
- libvlc_media_player_play(player->media_player);
+ libvlc_media_player_play(player->priv->media_player);
}
void
gtk_vlc_player_pause(GtkVlcPlayer *player)
{
- libvlc_media_player_pause(player->media_player);
+ libvlc_media_player_pause(player->priv->media_player);
}
gboolean
gtk_vlc_player_toggle(GtkVlcPlayer *player)
{
- if (libvlc_media_player_is_playing(player->media_player))
+ if (libvlc_media_player_is_playing(player->priv->media_player))
gtk_vlc_player_pause(player);
else
gtk_vlc_player_play(player);
- return (gboolean)libvlc_media_player_is_playing(player->media_player);
+ return (gboolean)libvlc_media_player_is_playing(player->priv->media_player);
}
void
gtk_vlc_player_stop(GtkVlcPlayer *player)
{
gtk_vlc_player_pause(player);
- libvlc_media_player_stop(player->media_player);
+ libvlc_media_player_stop(player->priv->media_player);
update_time(player, 0);
}
@@ -328,53 +388,56 @@ gtk_vlc_player_stop(GtkVlcPlayer *player)
void
gtk_vlc_player_seek(GtkVlcPlayer *player, gint64 time)
{
- libvlc_media_player_set_time(player->media_player, (libvlc_time_t)time);
+ libvlc_media_player_set_time(player->priv->media_player,
+ (libvlc_time_t)time);
}
void
gtk_vlc_player_set_volume(GtkVlcPlayer *player, gdouble volume)
{
- libvlc_audio_set_volume(player->media_player, (int)(volume*100.));
+ libvlc_audio_set_volume(player->priv->media_player, (int)(volume*100.));
}
GtkAdjustment *
gtk_vlc_player_get_time_adjustment(GtkVlcPlayer *player)
{
- return GTK_ADJUSTMENT(player->time_adjustment);
+ return GTK_ADJUSTMENT(player->priv->time_adjustment);
}
void
gtk_vlc_player_set_time_adjustment(GtkVlcPlayer *player, GtkAdjustment *adj)
{
- g_signal_handler_disconnect(G_OBJECT(player->time_adjustment),
- player->time_adj_on_value_changed_id);
+ g_signal_handler_disconnect(G_OBJECT(player->priv->time_adjustment),
+ player->priv->time_adj_on_value_changed_id);
- gtk_object_unref(player->time_adjustment);
- player->time_adjustment = GTK_OBJECT(adj);
- gtk_object_ref(player->time_adjustment);
+ g_object_unref(player->priv->time_adjustment);
+ player->priv->time_adjustment = GTK_OBJECT(adj);
+ g_object_ref_sink(player->priv->time_adjustment);
- player->time_adj_on_value_changed_id =
- g_signal_connect(G_OBJECT(player->time_adjustment), "value-changed",
+ player->priv->time_adj_on_value_changed_id =
+ g_signal_connect(G_OBJECT(player->priv->time_adjustment),
+ "value-changed",
G_CALLBACK(time_adj_on_value_changed), player);
}
GtkAdjustment *
gtk_vlc_player_get_volume_adjustment(GtkVlcPlayer *player)
{
- return GTK_ADJUSTMENT(player->volume_adjustment);
+ return GTK_ADJUSTMENT(player->priv->volume_adjustment);
}
void
gtk_vlc_player_set_volume_adjustment(GtkVlcPlayer *player, GtkAdjustment *adj)
{
- g_signal_handler_disconnect(G_OBJECT(player->volume_adjustment),
- player->vol_adj_on_value_changed_id);
+ g_signal_handler_disconnect(G_OBJECT(player->priv->volume_adjustment),
+ player->priv->vol_adj_on_value_changed_id);
- gtk_object_unref(player->volume_adjustment);
- player->volume_adjustment = GTK_OBJECT(adj);
- gtk_object_ref(player->volume_adjustment);
+ g_object_unref(player->priv->volume_adjustment);
+ player->priv->volume_adjustment = GTK_OBJECT(adj);
+ g_object_ref_sink(player->priv->volume_adjustment);
- player->vol_adj_on_value_changed_id =
- g_signal_connect(G_OBJECT(player->volume_adjustment), "value-changed",
+ player->priv->vol_adj_on_value_changed_id =
+ g_signal_connect(G_OBJECT(player->priv->volume_adjustment),
+ "value-changed",
G_CALLBACK(vol_adj_on_value_changed), player);
}
diff --git a/lib/gtk-vlc-player/gtk-vlc-player.h b/lib/gtk-vlc-player/gtk-vlc-player.h
index 969aa6d..ef504c1 100644
--- a/lib/gtk-vlc-player/gtk-vlc-player.h
+++ b/lib/gtk-vlc-player/gtk-vlc-player.h
@@ -4,8 +4,6 @@
#include <glib-object.h>
#include <gtk/gtk.h>
-#include <vlc/vlc.h>
-
G_BEGIN_DECLS
#define GTK_TYPE_VLC_PLAYER \
@@ -21,20 +19,13 @@ G_BEGIN_DECLS
#define GTK_VLC_PLAYER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_VLC_PLAYER, GtkVlcPlayerClass))
+/** @private */
+typedef struct _GtkVlcPlayerPrivate GtkVlcPlayerPrivate;
+
typedef struct _GtkVlcPlayer {
GtkAlignment parent_instance;
- GtkObject *time_adjustment;
- gulong time_adj_on_value_changed_id;
-
- GtkObject *volume_adjustment;
- gulong vol_adj_on_value_changed_id;
-
- libvlc_instance_t *vlc_inst;
- libvlc_media_player_t *media_player;
-
- gboolean isFullscreen;
- GtkWidget *fullscreen_window;
+ GtkVlcPlayerPrivate *priv; /**< @private */
} GtkVlcPlayer;
typedef struct _GtkVlcPlayerClass {