From 32c572145c09642fa515e96a413a6a6ccb604b24 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sat, 12 May 2012 21:03:13 +0200 Subject: make private gtk-vlc-player attributes private (well sort of...) and fix object destruction (dispose, finalize) * private attributes allow us to remove the vlc.h dependency from the class header (users of the header/widget might not have the header or correct flags to include it) * destruction using _dispose() and _finalize() handlers: vlc references are finalized, while Gtk objects are disposed * in order for reference counting on the GtkObjects to work, their reference counter must be explicitly initialized (side effect of g_object_ref_sink()) * don't use deprecated gtk_object_ref/unref() functions --- lib/gtk-vlc-player/gtk-vlc-player.c | 261 ++++++++++++++++++++++-------------- lib/gtk-vlc-player/gtk-vlc-player.h | 17 +-- 2 files changed, 166 insertions(+), 112 deletions(-) (limited to 'lib/gtk-vlc-player') 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 #include -#include - 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 { -- cgit v1.2.3