From: Thomas V. S. <tho...@us...> - 2002-02-03 21:12:35
|
Update of /cvsroot/gstreamer/gst-player/libs/gst/player In directory usw-pr-cvs1:/tmp/cvs-serv978/libs/gst/player Added Files: Makefile.am gstmediaplay.c gstmediaplay.h gstplayer-marshal.list gstplayer-private.h gstplayer.c gstplayer.h gstprefs.c gstprefs.h gststatusarea.c gststatusarea.h songinfo.c songinfo.h Log Message: the third player for those that lose count, this is a scrubbed version (with a librified back-end and some other things) of Company's hack of arik's rework of the original player also, a spec file is included which works (but too much gnome2 is drawn in, like ssl) and the pixmaps should be visible whether you run it uninstalled or installed. hope that makes you all feel warm inside. --- NEW FILE: Makefile.am --- ## Process this file with automake to produce Makefile.in $(libgstplayer_la_OBJECTS): \ gstplayer-marshal.h \ gstplayer-marshal.c lib_LTLIBRARIES = libgstplayer.la libgstplayer_la_SOURCES = \ gstplayer.c \ songinfo.c \ gststatusarea.c \ gstmediaplay.c \ gstprefs.c \ gstplayer-marshal.c libgstplayer_la_CFLAGS = $(GST_PLAYER_CFLAGS) -DPIXMAPS_INSTALLED=\""$(pkgdatadir)/pixmaps"\" noinst_HEADERS = \ gstplayer.h \ songinfo.h \ gstplayer-private.h \ gststatusarea.h \ gstprefs.h \ gstmediaplay.h \ gstplayer-marshal.h ## playlist.h \ gstplayer-marshal.h: gstplayer-marshal.list ( glib-genmarshal --prefix=gst_play_marshal $(srcdir)/gstplayer-marshal.list --header > gstplayer-marshal.tmp \ && mv gstplayer-marshal.tmp gstplayer-marshal.h ) \ || ( rm -f gstplayer-marshal.tmp && exit 1 ) gstplayer-marshal.c: gstplayer-marshal.h ( glib-genmarshal --prefix=gst_play_marshal $(srcdir)/gstplayer-marshal.list --body > gstplayer-marshal.tmp \ && mv gstplayer-marshal.tmp gstplayer-marshal.c ) \ || ( rm -f gstplayer-marshal.tmp && exit 1 ) EXTRA_DIST = \ gstplayer.h songinfo.h gststatusarea.h gstmediaplay.h gstprefs.h gstplayer-marshal.list DISTCLEANFILES = gstplayer-marshal.c gstplayer-marshal.h --- NEW FILE: gstmediaplay.c --- #include <gnome.h> #include "gstmediaplay.h" /* #include "playlist.h" */ #include "gstprefs.h" static void gst_media_play_class_init (GstMediaPlayClass *klass); static void gst_media_play_init (GstMediaPlay *play); void cb_open (GtkWidget *widget, GstMediaPlay *mplay); void cb_destroy (GObject object, GstMediaPlay *mplay); void cb_about (GtkWidget *widget, GstMediaPlay *mplay); static int window_key_press_event (GtkWidget *widget, GdkEventKey *event, GstMediaPlay *mplay); static void gst_media_play_slider_changed (GtkAdjustment *adj, GstMediaPlay *mplay); void gst_media_play_play (GtkWidget *widget, GstMediaPlay *mplay); void gst_media_play_pause (GtkWidget *widget, GstMediaPlay *mplay); void gst_media_play_stop (GtkWidget *widget, GstMediaPlay *mplay); void gst_media_play_next (GtkWidget *widget, GstMediaPlay *mplay); static void gst_media_play_frame_displayed (GstMediaPlay *mplay); void gst_media_play_set_fullscreen (GstMediaPlay *mplay); gchar* gst_pixmap_path (gchar *pixmap_fn); gchar *current_directory; static GObject *parent_class = NULL; static GnomeUIInfo file_menu [] = { GNOMEUIINFO_MENU_OPEN_ITEM (cb_open, NULL), GNOMEUIINFO_MENU_EXIT_ITEM (cb_destroy, NULL), GNOMEUIINFO_END }; static GnomeUIInfo edit_menu [] = { GNOMEUIINFO_MENU_PREFERENCES_ITEM (prefs_dialog, NULL), GNOMEUIINFO_END }; static GnomeUIInfo help_menu [] = { GNOMEUIINFO_MENU_ABOUT_ITEM (cb_about, NULL), GNOMEUIINFO_END }; static GnomeUIInfo main_menu [] = { GNOMEUIINFO_MENU_FILE_TREE (file_menu), GNOMEUIINFO_MENU_EDIT_TREE (edit_menu), GNOMEUIINFO_MENU_HELP_TREE (help_menu), GNOMEUIINFO_END }; #ifdef USE_GLIB2 GType gst_media_play_get_type (void) { static GType play_type = 0; if (!play_type) { static const GTypeInfo style_info = { sizeof (GstMediaPlayClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gst_media_play_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GstMediaPlay), 0, /* n_preallocs */ (GInstanceInitFunc) gst_media_play_init, }; play_type = g_type_register_static (G_TYPE_OBJECT, "GstMediaPlay", &style_info, 0); } return play_type; } #else /* !USE_GLIB2 */ GtkType gst_media_play_get_type (void) { static GtkType play_type = 0; if (!play_type) { static const GtkTypeInfo play_info = { "GstMediaPlay", sizeof (GstMediaPlay), sizeof (GstMediaPlayClass), (GtkClassInitFunc) gst_media_play_class_init, (GtkObjectInitFunc) gst_media_play_init, NULL, NULL, (GtkClassInitFunc) NULL, }; play_type = gtk_type_unique (gtk_object_get_type(), &play_info); } return play_type; } #endif /* !USE_GLIB2 */ /* delete me? */ static void gst_media_play_class_init (GstMediaPlayClass *klass) { #ifdef USE_GLIB2 GObjectClass *object_class; parent_class = gtk_type_class (G_TYPE_OBJECT); object_class = (GObjectClass*) klass; #else /* !USE_GLIB2 */ GtkObjectClass *object_class; parent_class = gtk_type_class (gtk_object_get_type ()); object_class = (GtkObjectClass*) klass; #endif /* !USE_GLIB2 */ } static void gst_media_play_init (GstMediaPlay *mplay) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *button; GtkWidget *pixmap; GtkTooltips *tooltips; mplay->play = gst_play_new (); mplay->window = gnome_app_new ("gstmediaplay", "- GstMediaPlay"); g_signal_connect (G_OBJECT (mplay->window), "destroy", G_CALLBACK (cb_destroy), NULL); g_signal_connect (G_OBJECT (mplay->window), "key_press_event", G_CALLBACK (window_key_press_event), mplay); gnome_app_create_menus_with_data (GNOME_APP (mplay->window), main_menu, mplay); vbox = gtk_vbox_new (0, 0); gnome_app_set_contents (GNOME_APP (mplay->window), vbox); mplay->video_hbox = gtk_hbox_new (1, 0); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (mplay->video_hbox), 1, 1, 0); mplay->video_widget = gtk_socket_new (); gtk_container_add (GTK_CONTAINER (mplay->video_hbox), mplay->video_widget); mplay->adjustment = G_OBJECT(gtk_adjustment_new (0, 0, 110, 1, 10, 10)); mplay->slider = gtk_hscale_new (GTK_ADJUSTMENT (mplay->adjustment)); gtk_scale_set_draw_value (GTK_SCALE (mplay->slider), FALSE); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (mplay->slider), 0, 0, 0); g_signal_connect (G_OBJECT (mplay->adjustment), "value_changed", GTK_SIGNAL_FUNC (gst_media_play_slider_changed), mplay); mplay->button_hbox = gtk_hbox_new (1, 0); gtk_box_pack_start (GTK_BOX (vbox), mplay->button_hbox, 0, 1, 0); tooltips = gtk_tooltips_new (); button = gtk_button_new (); pixmap = gnome_pixmap_new_from_file (gst_pixmap_path ("play.xpm")); gtk_container_add (GTK_CONTAINER (button), pixmap); gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), button, "Play", NULL); gtk_box_pack_start (GTK_BOX (mplay->button_hbox), button, 1, 1, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gst_media_play_play), mplay); button = gtk_button_new (); pixmap = gnome_pixmap_new_from_file (gst_pixmap_path ("pause.xpm")); gtk_container_add (GTK_CONTAINER (button), pixmap); gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), button, "Pause", NULL); gtk_box_pack_start (GTK_BOX (mplay->button_hbox), button, 1, 1, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gst_media_play_pause), mplay); button = gtk_button_new (); pixmap = gnome_pixmap_new_from_file (gst_pixmap_path ("stop.xpm")); gtk_container_add (GTK_CONTAINER (button), pixmap); gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), button, "Stop", NULL); gtk_box_pack_start (GTK_BOX (mplay->button_hbox), button, 1, 1, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gst_media_play_stop), mplay); button = gtk_button_new (); pixmap = gnome_pixmap_new_from_file (gst_pixmap_path ("next.xpm")); gtk_container_add (GTK_CONTAINER (button), pixmap); gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), button, "Next", NULL); gtk_box_pack_start (GTK_BOX (mplay->button_hbox), button, 1, 1, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gst_media_play_next), mplay); mplay->status = gst_status_area_new (); gst_status_area_set_state (mplay->status, GST_STATUS_AREA_STATE_INIT); gst_status_area_set_playtime (mplay->status, "00:00 / 00:00"); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (mplay->status), FALSE, TRUE, 0); gtk_widget_show_all (mplay->window); gtk_widget_hide (mplay->video_hbox); mplay->last_time = 0; mplay->fullscreen_active = FALSE; mplay->stolen = FALSE; mplay->current_song = NULL; mplay->repeat = FALSE; current_directory = NULL; } GstMediaPlay* gst_media_play_new (void) { return GST_MEDIA_PLAY (g_object_new (GST_TYPE_MEDIA_PLAY, NULL)); } static void gst_media_play_have_size (GstElement *element, guint width, guint height, GstMediaPlay *mplay) { mplay->source_width = width; mplay->source_height = height; gtk_widget_set_usize (mplay->video_widget, width, height); } static void gst_media_play_update_status_area (gulong current_time, gulong total_time, GstMediaPlay *mplay) { gchar time[14]; sprintf (time, "%02lu:%02lu / %02lu:%02lu", current_time / 60, current_time % 60, total_time / 60, total_time % 60); gst_status_area_set_playtime (mplay->status, time); } static void gst_media_play_update_slider (GstMediaPlay *mplay, GtkAdjustment *adjustment, gfloat value) { gtk_signal_handler_block_by_func (GTK_OBJECT (adjustment), GTK_SIGNAL_FUNC (gst_media_play_slider_changed), mplay); gtk_adjustment_set_value (adjustment, value); gtk_signal_handler_unblock_by_func (GTK_OBJECT (adjustment), GTK_SIGNAL_FUNC (gst_media_play_slider_changed), mplay); } static void gst_media_play_video_frame_displayed (GstMediaPlay *mplay) { GstElement *video_show; /* video_show = gst_play_get_video_show (); if (!mplay->stolen) { gtk_widget_realize (mplay->video_widget); gtk_socket_steal (GTK_SOCKET (mplay->video_widget), gst_util_get_int_arg (G_OBJECT (video_show), "xid")); gtk_widget_show (mplay->video_widget); mplay->stolen = TRUE; } gtk_widget_show (mplay->video_hbox); */ } static void gst_media_play_frame_displayed (GstMediaPlay *mplay) { gulong current_time; gulong total_time; gulong size, current_offset; /*current_time = gst_play_get_media_current_time (); total_time = gst_play_get_media_total_time (); size = gst_play_get_media_size (); current_offset = gst_play_get_media_offset (); if (current_time != mplay->last_time) { //gst_media_play_update_status_area (current_time, total_time, mplay); //gst_media_play_update_slider (mplay, GTK_ADJUSTMENT (mplay->adjustment), current_offset*100.0/size); mplay->last_time = current_time; }*/ } static void gst_media_play_slider_changed (GtkAdjustment *adj, GstMediaPlay *mplay) { gulong size; /*size = gst_play_get_media_size (); gst_play_media_seek ((int)(adj->value*size/100.0));*/ } void cb_about (GtkWidget *widget, GstMediaPlay *mplay) { static GtkWidget *about; const gchar *authors[] = {"Erik Walthinsen <om...@cs...>", "Wim Taymans <wim...@tv...>", "Richard Boulton <ri...@ta...>", "Chris Emerson (PPC port)", "Ronald Bultje <rb...@ro...>", "Arik Devens <ar...@gn...>", NULL}; if (about != NULL) { gdk_window_raise (about->window); gdk_window_show (about->window); return; } #ifdef USE_GLIB2 about = gnome_about_new ("GstMediaPlay", GST_PLAYER_VERSION, "(C) 1999-2001 Erik Walthinsen, Arik Devens", "A generic media player for the gstreamer streaming media framework.", (const char **)authors, NULL, NULL, NULL); #else /* !USE_GLIB2 */ about = gnome_about_new ("GstMediaPlay", GST_PLAYER_VERSION, "(C) 1999-2001 Erik Walthinsen, Arik Devens", (const char **)authors, "A generic media player for the gstreamer streaming media framework.", NULL); #endif /* !USE_GLIB2 */ g_signal_connect (G_OBJECT (about), "destroy", G_CALLBACK (gtk_widget_destroyed), &about); gnome_dialog_set_parent (GNOME_DIALOG (about), GTK_WINDOW (mplay->window)); gtk_widget_show (about); } typedef struct { GtkWidget *selection; GstMediaPlay *mplay; } file_select; static void on_load_file_selected (GtkWidget *button, file_select *data) { GtkWidget *file_selection; GstMediaPlay *mplay; gchar *filename; file_selection = data->selection; mplay = data->mplay; filename = (gchar *) gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_selection)); current_directory = g_strdup_printf ("%s", filename); /* FIXME: ugly hack starts here */ g_object_set(mplay->play, "state", GST_STATE_NULL, NULL); g_object_unref (mplay->play); mplay->play = gst_play_new_from_uri (filename); /* g_object_set(mplay->play, "URI", filename, NULL); */ /* FIXME: end ugly hack */ /*playlist_start_new_list (); gst_media_play_add_file_to_list (g_strdup_printf ("%s", filename)); */ } void cb_open (GtkWidget *widget, GstMediaPlay *mplay) { GtkWidget *file_selector; file_select *file_data = g_new0 (file_select, 1); file_selector = gtk_file_selection_new ("Please select a file to load."); file_data->selection = file_selector; file_data->mplay = mplay; g_signal_connect (G_OBJECT (GTK_FILE_SELECTION(file_selector)->ok_button), "clicked", G_CALLBACK (on_load_file_selected), file_data); /* Ensure that the dialog box is destroyed when the user clicks a button. */ gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (file_selector)->ok_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) file_selector); gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (file_selector)->cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) file_selector); if (current_directory) { gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_selector), current_directory); } /* Display that dialog */ gtk_widget_show (file_selector); } GList * next_song_to_play (GstMediaPlay *mplay, gboolean play_next) { /* GList *list = NULL; if (mplay->current_song == NULL) mplay->current_song = playlist_current_playlist (); if (play_next) { list = mplay->current_song->next; if ((list == NULL) && (mplay->repeat == TRUE)) list = playlist_current_playlist (); } else list = mplay->current_song; return list; */ } void gst_media_play_play (GtkWidget *widget, GstMediaPlay *mplay) { g_object_set (mplay->play, "state", GST_STATE_PLAYING, NULL); } void gst_media_play_pause (GtkWidget *widget, GstMediaPlay *mplay) { g_object_set (mplay->play, "state", GST_STATE_PAUSED, NULL); } void gst_media_play_stop (GtkWidget *widget, GstMediaPlay *mplay) { g_object_set (mplay->play, "state", GST_STATE_READY, NULL); } void gst_media_play_next (GtkWidget *widget, GstMediaPlay *mplay) { /* GList *list = NULL; SongInfo *info; GstPlayReturn ret; list = next_song_to_play (mplay, TRUE); if (list != NULL) { info = (SongInfo *)list->data; gtk_idle_remove (mplay->idle); gst_play_stop (mplay->play); ret = gst_play_set_uri (mplay->play, info->filename); if (ret != GST_PLAY_OK) return; gst_play_play (mplay->play); mplay->idle = gtk_idle_add ((GtkFunction) cb_idle_play, mplay); gtk_window_set_title (GTK_WINDOW (mplay->window), g_strdup_printf ("%s - %s - GstMediaPlay", info->artist ? info->artist : "Unknown", info->song ? info->song : "Unknown")); gst_status_area_set_state (mplay->status, GST_STATUS_AREA_STATE_PLAYING); mplay->state = GST_PLAY_PLAYING; mplay->current_song = list; if (mplay->repeat == FALSE) { list = next_song_to_play (mplay, TRUE); if (list == NULL) { } } } */ } void cb_destroy (GObject object, GstMediaPlay *mplay) { /* if (mplay->play->state == GST_STATE_PLAYING) { gst_play_stop (mplay->play); } */ gtk_main_quit (); } void gst_media_play_add_file_to_list (char *uri) { /* SongInfo *info; info = playlist_add_file (uri); playlist_add_to_playlist (info); */ } static int window_key_press_event (GtkWidget *widget, GdkEventKey *event, GstMediaPlay *mplay) { guint state, playstate; state = event->state; switch (event->keyval) { case GDK_space: g_object_get(mplay->play, "state", &playstate, NULL); if (playstate == GST_STATE_PLAYING) { gst_media_play_pause (widget, mplay); } else if (playstate == GST_STATE_PAUSED) { gst_media_play_play (widget, mplay); } break; case GDK_m: gst_media_play_set_fullscreen (mplay); break; case GDK_Return: if (state & GDK_MOD1_MASK) gst_media_play_set_fullscreen (mplay); break; } return TRUE; } static int fullscreen_key_press_event (GtkWidget *widget, GdkEventKey *event, GstMediaPlay *mplay) { switch (event->keyval) { case GDK_Escape: gst_media_play_set_fullscreen (mplay); break; case GDK_q: gst_media_play_set_fullscreen (mplay); break; } return TRUE; } void gst_media_play_set_fullscreen (GstMediaPlay *mplay) { GdkWindow *gdk_window; gint client_x, client_y, root_x, root_y; gint width, height; gint screen_width, screen_height; /* how big do we want fullscreen to be ? */ GdkCursor* cursor; GdkPixmap *source; GdkPixmap *mask; GdkColor fg = {0, 0, 0, 0}; GdkColor bg = {0, 0, 0, 0}; static unsigned char cursor_bits[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; static unsigned char cursormask_bits[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; gdk_window = mplay->window->window; if (mplay->source_width || mplay->source_height) { if (!mplay->fullscreen_active) { gtk_widget_hide (GNOME_APP (mplay->window)->menubar); gtk_widget_hide (mplay->slider); gtk_widget_hide (mplay->button_hbox); gtk_widget_hide (GTK_WIDGET (mplay->status)); gdk_window_get_origin (gdk_window, &root_x, &root_y); gdk_window_get_geometry (gdk_window, &client_x, &client_y, &width, &height, NULL); /* FIXME : this is a quick hack to play only on the first screen for dualheads * we detect dualhead by looking for an 8:3 aspect ratio */ screen_width = gdk_screen_width (); screen_height = gdk_screen_height (); if (screen_width * 3 == screen_height * 8) { fprintf (stderr, "Dualhead assumed - fixing aspect ratio\n"); screen_width /= 2; } gdk_window_move (gdk_window, -client_x, -client_y); gtk_widget_set_usize (mplay->video_widget, gdk_screen_width () + 1, gdk_screen_height () + 1); source = gdk_bitmap_create_from_data (NULL, cursor_bits, 16, 16); mask = gdk_bitmap_create_from_data (NULL, cursormask_bits, 16, 16); cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 8, 8); gdk_pixmap_unref (source); gdk_pixmap_unref (mask); gdk_window_set_cursor (gdk_window, cursor); mplay->x = root_x - client_x; mplay->y = root_y - client_y; mplay->width = width; mplay->height = height; mplay->fullscreen_active = TRUE; mplay->fullscreen_connection_id = gtk_signal_connect (GTK_OBJECT (mplay->window), "key_press_event", (GtkSignalFunc) fullscreen_key_press_event, mplay); } else { gtk_widget_show (GNOME_APP (mplay->window)->menubar); gtk_widget_show (mplay->slider); gtk_widget_show (mplay->button_hbox); gtk_widget_show (GTK_WIDGET (mplay->status)); /* yah yah */ /* g_print("Are we getting here (in fullscreen)"); */ gtk_widget_queue_resize (mplay->video_hbox); gdk_window_move (gdk_window, mplay->x, mplay->y); gtk_widget_set_usize (mplay->video_widget, mplay->source_width, mplay->source_height); gdk_window_set_cursor (gdk_window, NULL); gtk_signal_disconnect (GTK_OBJECT (mplay->window), mplay->fullscreen_connection_id); mplay->fullscreen_active = FALSE; } } } /* return path to a gst pixmap * try the hard-coded path first * if that doesn't exist, use the one based on prefix */ gchar* gst_pixmap_path (gchar *pixmap_fn) { gchar *path; path = g_strconcat (PIXMAPS_UNINSTALLED, "/", pixmap_fn, NULL); if (access (path, R_OK) != 0) { g_free (path); path = g_strconcat(PIXMAPS_INSTALLED, "/", pixmap_fn, NULL); } return path; } --- NEW FILE: gstmediaplay.h --- #ifndef __GST_MEDIA_PLAY_H__ #define __GST_MEDIA_PLAY_H__ #include "gstplayer.h" #include "gststatusarea.h" #define GST_TYPE_MEDIA_PLAY (gst_media_play_get_type()) #define GST_MEDIA_PLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_PLAY, GstMediaPlay)) #define GST_MEDIA_PLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_PLAY, GstMediaPlayClass)) #define GST_IS_MEDIA_PLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_PLAY)) #define GST_IS_MEDIA_PLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_PLAY)) #ifdef USE_GLIB2 #define GST_MEDIA_PLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MEDIA_PLAY, GstMediaPlayClass)) #endif /* USE_GLIB2 */ typedef struct _GstMediaPlay GstMediaPlay; typedef struct _GstMediaPlayClass GstMediaPlayClass; struct _GstMediaPlay { GObject parent; GstPlay *play; GtkWidget *window; GtkWidget *slider; GstStatusArea *status; GObject *adjustment; GtkWidget *video_widget; GtkWidget *video_hbox; GtkWidget *button_hbox; gboolean fullscreen_active; guint fullscreen_connection_id; gboolean stolen; gulong last_time; gint x, y, width, height; guint source_width, source_height; guint idle; GList *current_song; gboolean repeat; }; struct _GstMediaPlayClass { GObjectClass parent_class; }; #ifdef USE_GLIB2 GType gst_media_play_get_type (void); #else /* !USE_GLIB2 */ GtkType gst_media_play_get_type (void); #endif /* !USE_GLIB2 */ GstMediaPlay* gst_media_play_new (void); void gst_media_play_add_file_to_list (char *uri); void gst_media_play_start_uri (GstMediaPlay *mplay, const guchar *uri); #endif /* __GST_MEDIA_PLAY_H__ */ --- NEW FILE: gstplayer-marshal.list --- VOID:STRING,POINTER,POINTER VOID:INT,INT --- NEW FILE: gstplayer-private.h --- #ifndef __GSTPLAY_PRIVATE_H__ #define __GSTPLAY_PRIVATE_H__ #include <gst/gst.h> typedef struct _GstPlayPrivate GstPlayPrivate; struct _GstPlayPrivate { GstPlayState state; GstElement *pipeline; GstElement *video_sink; GstElement *audio_sink; GstElement *video_show; //GtkWidget *video_widget; GstElement *filesrc; GstElement *cache; GstElement *typefind; guchar *uri; gboolean muted; gboolean can_seek; GstElement *offset_element; GstElement *bit_rate_element; GstElement *media_time_element; GstElement *current_time_element; guint source_width; guint source_height; }; #endif /* __GSTPLAY_PRIVATE_H__ */ --- NEW FILE: gstplayer.c --- /* #include <gtk/gtk.h> */ #include "gstplayer.h" #include "gstplayer-marshal.h" /* This is a 1:1 copy from gst/gstpropsprivate. * It is needed to parse INFO_EVENTs. * * In case you are wondering: * This is probably a bug and needs a big FIXME */ #ifndef __GST_PROPS_PRIV_H__ #include <gst/gstprops.h> #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID) typedef struct _GstPropsEntry GstPropsEntry; struct _GstPropsEntry { GQuark propid; GstPropsId propstype; union { /* flat values */ gboolean bool_data; guint32 fourcc_data; gint int_data; gfloat float_data; /* structured values */ struct { GList *entries; } list_data; struct { gchar *string; } string_data; struct { gint min; gint max; } int_range_data; struct { gfloat min; gfloat max; } float_range_data; } data; }; #endif /* __GST_PROPS_PRIV_H__ */ /* end of gst/gstpropsprivate.h */ enum { INFORMATION, STATE_CHANGE, LAST_SIGNAL }; enum { ARG_0, ARG_URI, ARG_STATE, /* FILL ME */ }; /* GObject/GType variables */ static GstElementClass * parent_class = NULL; static guint gst_play_signals[LAST_SIGNAL] = { 0 }; /* GObject/GType initialization functions */ static void gst_play_init (GstPlay *play); static void gst_play_class_init (GstPlayClass *klass); /* properties */ static void gst_play_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_play_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); /* pipeline signal callbacks */ static void callback_pipeline_event (GstElement *element, GstEvent *event, GstPlay* play); static void callback_pipeline_state_change (GstElement *element, GstElementState old, GstElementState state, GstPlay* play); /* idle callback function */ gboolean gst_play_idle_callback (GstPlay *play); /* couples/decouples the state of pipeline and Gstplay */ static void gst_play_set_couple_state (GstPlay *play, gboolean new_couple); /* change state */ static void gst_play_change_pipeline_state (GstPlay *play, GstElementState state); /* FIXME: Make output and input elements pluggable */ static GstElement * get_default_audio_element (void); static GstElement * get_default_video_element (void); /* Enumerations that need a GType because they're arguments */ /* FIXME: This shouldn't go here but it is supposed to break anyway if someone implements this in the core */ #define GST_TYPE_ELEMENT_STATE (gst_element_state_get_type()) static GType gst_element_state_get_type(void) { static GType element_state_type = 0; static GEnumValue element_state[] = { { GST_STATE_NULL, "0", "null" }, { GST_STATE_READY, "1", "ready" }, { GST_STATE_PAUSED, "2", "paused" }, { GST_STATE_PLAYING, "3", "playing" }, { 0, NULL, NULL }, }; if (!element_state_type) { element_state_type = g_enum_register_static("GstElementState", element_state); } return element_state_type; } GType gst_play_get_type (void) { static GType play_type = 0; if (!play_type) { static const GTypeInfo play_info = { sizeof (GstPlayClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gst_play_class_init, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GstPlay), 0, /* n_preallocs */ (GInstanceInitFunc) gst_play_init, }; play_type = g_type_register_static (G_TYPE_OBJECT, "GstPlay", &play_info, 0); } return play_type; } static void gst_play_class_init(GstPlayClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); /* initialize parent class */ parent_class = g_type_class_ref(GST_TYPE_OBJECT); /* initialize signal functions */ klass->information = NULL; klass->state_changed = NULL; /* properties */ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_play_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_play_get_property); g_object_class_install_property (gobject_class, ARG_URI, g_param_spec_string ("URI", "location", "name of the file to play", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, ARG_STATE, g_param_spec_enum ("state", "State", "Null, Ready, Paused or Playing", GST_TYPE_ELEMENT_STATE, GST_STATE_NULL, G_PARAM_READWRITE)); /* initialize signals */ gst_play_signals[INFORMATION] = g_signal_new ("information", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstPlayClass, information), NULL, NULL, gst_play_marshal_VOID__STRING_POINTER_POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); gst_play_signals[STATE_CHANGE] = g_signal_new ("state_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstPlayClass, state_changed), NULL, NULL, gst_play_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); } /* initializes the pipeline that should be used. * FIXME: Should this go into the _new function to allow returning NULL * if something fails? */ static void gst_play_init(GstPlay *play) { GstElement *autoplugger; /* init pipeline */ play->pipeline = gst_pipeline_new ("main_pipeline"); g_assert (GST_IS_PIPELINE(play->pipeline)); /* connect to pipeline events */ g_signal_connect (G_OBJECT (play->pipeline), "event", G_CALLBACK (callback_pipeline_event), play); g_signal_connect (G_OBJECT (play->pipeline), "state_change", G_CALLBACK (callback_pipeline_state_change), play); /* create those elements */ play->source = gst_elementfactory_make ("filesrc", "source"); autoplugger = gst_elementfactory_make ("spider", "autoplugger"); play->video_sink = get_default_video_element(); play->audio_sink = get_default_audio_element(); /* add those elements */ gst_bin_add (GST_BIN (play->pipeline), play->source); gst_bin_add (GST_BIN (play->pipeline), autoplugger); gst_bin_add (GST_BIN (play->pipeline), play->video_sink); gst_bin_add (GST_BIN (play->pipeline), play->audio_sink); /* and connect them */ gst_element_connect_elements (play->source, autoplugger); gst_element_connect_elements (autoplugger, play->video_sink); gst_element_connect_elements (autoplugger, play->audio_sink); /* set variables */ play->state = gst_element_get_state (play->pipeline); play->state_coupled = TRUE; } /* GList iteration function to create information events for props */ static void create_event_from_props(GstPropsEntry *entry, GstPlay *play) { guchar *name; GType *type; gpointer value; name = (guchar*) g_quark_to_string (entry->propid); /* g_print("creating event for %s:", name); */ /* FIXME: get the other types working */ switch (entry->propstype) { case GST_PROPS_INT_ID: type = (GType*) G_TYPE_INT; value = (gpointer) &entry->data.int_data; /* g_print("%d\n", *((int*) value)); */ break; case GST_PROPS_STRING_ID: type = (GType*) G_TYPE_STRING; value = entry->data.string_data.string; /* g_print("%s\n", (gchar*) value); */ break; case GST_PROPS_FLOAT_ID: type = (GType*) G_TYPE_FLOAT; value = (gpointer) &entry->data.float_data; /* g_print("%f\n", *((float*) value)); */ break; default: g_warning("cannot create information event from these caps"); return; } /* emit signal */ g_signal_emit (G_OBJECT (play), gst_play_signals[INFORMATION], 0, name, type, value); /* CHECKME: must any data be freed? */ } /* pipeline signal callbacks */ static void callback_pipeline_event (GstElement *element, GstEvent *event, GstPlay* play) { GstProps *props; GstPipeline *pipeline = GST_PIPELINE (element); /* check that the input is ok */ g_assert (pipeline != NULL); g_assert (GST_IS_PIPELINE (pipeline)); g_assert (play != NULL); g_assert (GST_IS_PLAY (play)); g_assert (pipeline == GST_PIPELINE (play->pipeline)); g_return_if_fail (event != NULL); g_return_if_fail (GST_IS_EVENT (event)); /* switch diferent elements */ switch (GST_EVENT_TYPE (event)) { /* create an "information" event for every prop in the pipeline event */ case GST_EVENT_INFO: props = GST_EVENT_INFO_PROPS (event); g_list_foreach (props->properties, (GFunc) create_event_from_props, play); break; default: break; } } /* callback on changing states * makes the pipeline state and the state of the GstPlay object match */ static void callback_pipeline_state_change (GstElement *element, GstElementState old, GstElementState state, GstPlay* play) { GstElementState old_state; /* check that the input is ok */ g_assert (element != NULL); g_assert (GST_IS_ELEMENT (element)); g_assert (play != NULL); g_assert (GST_IS_PLAY (play)); g_assert (element == GST_ELEMENT (play->pipeline)); /* don't care if states aren't coupled */ if (!play->state_coupled) return; /* don't care if the state hasn't changed */ /* g_print("state change\n"); */ if (state == play->state) return; /* change state */ old_state = play->state; play->state = state; /* do additional stuff depending on state */ switch (state) { case GST_STATE_PLAYING: /* g_print("idle func added\n"); */ g_idle_add ((GSourceFunc) gst_play_idle_callback, play); break; default: /* g_print("idle func removed\n"); */ g_idle_remove_by_data(play); break; } g_signal_emit (G_OBJECT (play), gst_play_signals[STATE_CHANGE], 0, old_state, play->state); } GstPlay * gst_play_new (void) { return g_object_new (GST_TYPE_PLAY, NULL); } GstPlay * gst_play_new_from_uri (const guchar *uri) { GstPlay * play; play = gst_play_new(); g_object_set (G_OBJECT (play), "URI", uri, NULL); return play; } static GstElement * get_default_audio_element (void) { GstElement* audio_sink; audio_sink = gst_elementfactory_make ("osssink", "play_audio"); /* g_object_set(G_OBJECT(audio_sink), "fragment", 256, NULL); */ return audio_sink; } static GstElement * get_default_video_element (void) { GstElement *video_sink; GstElement *video_show; GstElement *colorspace; video_sink = gst_elementfactory_make ("bin", "video_bin"); g_return_if_fail (video_sink != NULL); video_show = gst_elementfactory_make ("xvideosink", "show"); g_return_if_fail (video_show != NULL); gst_bin_add (GST_BIN (video_sink), video_show); colorspace = gst_elementfactory_make ("colorspace", "colorspace"); if (colorspace == NULL) { g_warning ("could not create the 'colorspace' element, doing without"); gst_element_add_ghost_pad (video_sink, gst_element_get_pad (video_show, "sink"), "sink"); } else { GST_FLAG_SET (video_sink, GST_ELEMENT_THREAD_SUGGESTED); gst_bin_add (GST_BIN (video_sink), colorspace); gst_element_connect (colorspace, "src", video_show, "sink"); gst_element_add_ghost_pad (video_sink, gst_element_get_pad (colorspace, "sink"), "sink"); } return video_sink; } /* idle function callback */ gboolean gst_play_idle_callback(GstPlay *play) { gboolean ret; ret = gst_bin_iterate (GST_BIN (play->pipeline)); if (!ret) { /* g_print("idle func removing itself\n"); */ } return ret; } /* couples or decouples the pipeline state from the GstPlay state. */ static void gst_play_set_couple_state (GstPlay *play, gboolean new_couple) { /* sanity checks */ g_return_if_fail(play != NULL); g_return_if_fail(GST_IS_PLAY (play)); /* return if nothing must be done */ if (new_couple == play->state_coupled) return; /* set new state */ play->state_coupled = new_couple; /* set play state to pipeline state if coupled */ if (new_couple) { callback_pipeline_state_change(play->pipeline, play->state, gst_element_get_state (GST_ELEMENT (play->pipeline)), play); } } /* changes the state of the pipeline * function is needed, because STATE_CHANGE signals don't work somehow. */ static void gst_play_change_pipeline_state (GstPlay *play, GstElementState state) { GstElementState old_state = gst_element_get_state( GST_ELEMENT(play->pipeline)); gst_element_set_state( GST_ELEMENT(play->pipeline), state); /* FIXME: If SMP works sometime, don't do this anymore. */ callback_pipeline_state_change( GST_ELEMENT(play->pipeline), old_state, gst_element_get_state( GST_ELEMENT(play->pipeline)), play); } static void gst_play_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstPlay *play = GST_PLAY (object); gchar *location; /* it's not null if we got it, but it might not be ours */ g_return_if_fail (GST_IS_PLAY (play)); /*g_print("%d\n", prop_id);*/ switch (prop_id) { case ARG_URI: g_object_get (play->source, "location", &location, NULL); /* somebody make the spider handle new streams, plz */ if (location != NULL) { g_warning ("This property is not working. Expect segfault. or weird behaviour."); /* return; */ } g_object_set (play->source, "location", g_value_get_string (value), NULL); break; case ARG_STATE: gst_play_change_pipeline_state (play, g_value_get_enum (value)); /* gst_element_set_state (GST_ELEMENT (play->pipeline), g_value_get_enum (value)); */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_play_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstPlay *play = GST_PLAY (object); gchar *location; /* it's not null if we got it, but it might not be ours */ g_return_if_fail (GST_IS_PLAY (play)); switch (prop_id) { case ARG_URI: g_object_get (play->source, "location", &location, NULL); g_value_set_string (value, location); break; case ARG_STATE: g_value_set_enum (value, gst_element_get_state (GST_ELEMENT (play->pipeline))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } --- NEW FILE: gstplayer.h --- #ifndef __GSTPLAY_H__ #define __GSTPLAY_H__ #include <gst/gst.h> /* * GstPlay is a simple class for audio and video playback. * It's job is to get the media (supplied by a URI) played. * More specific it should get the media from source to the output elements. * How that is done should not be relevant for developers using this class. * A user using this class should not have to know very much about how * GStreamer works, other than that it plays back media. * Additionally it supplies signals to get information about the current * playing state. */ /* disabled in the hope that using GstElementState is enough */ /* typedef enum { /* after errors or before loading a file */ /*GST_PLAY_EMPTY, /* states like gst states */ /*GST_PLAY_STOPPED, GST_PLAY_PAUSED, GST_PLAY_PLAYING, } GstPlayState; */ typedef enum { GST_PLAY_OK, GST_PLAY_UNKNOWN_MEDIA, GST_PLAY_CANNOT_PLAY, GST_PLAY_ERROR, } GstPlayReturn; #define GST_TYPE_PLAY (gst_play_get_type()) #define GST_PLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAY, GstPlay)) #define GST_PLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAY, GstPlayClass)) #define GST_IS_PLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAY)) #define GST_IS_PLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY)) #define GST_PLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PLAY, GstPlayClass)) typedef struct _GstPlayInfo GstPlayInfo; typedef struct _GstPlay GstPlay; typedef struct _GstPlayClass GstPlayClass; struct _GstPlay { GObject parent; GstElement * pipeline; GstElement * video_sink; GstElement * audio_sink; GstElement * source; /* FIXME: Do we need the next two? */ /* the current state of this object */ GstElementState state; /* wether or not the state is the same as the pipeline's * It's only used for internal things like autoplugging */ gboolean state_coupled; /* Should GstPlay support muting or be simpler? gboolean muted; */ }; struct _GstPlayClass { GObjectClass parent_class; /* signals */ void (*information) (GstPlay* play, guchar *name, GType *type, gpointer value); void (*state_changed) (GstPlay* play, GstElementState old_state, GstElementState new_state); }; GType gst_play_get_type (void); /* setup the player */ GstPlay * gst_play_new (void); GstPlay * gst_play_new_from_uri (const guchar *uri); #endif /* __GSTPLAY_H__ */ --- NEW FILE: gstprefs.c --- #include <gnome.h> #include "gstmediaplay.h" #include "gstprefs.h" void prefs_dialog (GtkWidget *widget, GstMediaPlay *mplay) { /* g_print("Prefs"); */ /* popup prefs dialog */ GtkWidget* dialog; GtkWidget* vbox; GtkLabel* prefslabel; GtkLabel* audiolabel; GtkLabel* videolabel; GtkLabel* active_audio_description; GtkLabel* active_video_description; GtkWidget* audio_combo; GtkWidget* video_combo; GtkWidget* audio_config_button; GtkWidget* video_config_button; GtkWidget* prefstable; int reply; dialog = gnome_dialog_new("Preferences", GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_APPLY, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_close(GNOME_DIALOG(dialog), TRUE); gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE); /* do a 4x4 layout */ /* vbox is supplied by dialog, thankfully :) */ /* blank space before table */ prefslabel = gtk_label_new("Preferences"); /* table for selecting A/V sinks */ /* 2C*3R * label label * audio combo video combo * label label */ prefstable = gtk_table_new(3, 2, FALSE); audiolabel = gtk_label_new("Audio output plugin"); videolabel = gtk_label_new("Video output plugin"); audio_combo = gtk_combo_new(); video_combo = gtk_combo_new(); audio_config_button = gtk_button_new_with_label("Configure audio output"); video_config_button = gtk_button_new_with_label("Configure video output"); gtk_table_attach(GTK_TABLE(prefstable), audiolabel, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(prefstable), videolabel, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(prefstable), audio_combo, 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(prefstable), video_combo, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(prefstable), audio_config_button, 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(prefstable), video_config_button, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), prefslabel, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), prefstable, TRUE, TRUE, 0); /* call function to read current configuration & set dialog accordingly */ /* also populate option buttons with list of plugins */ gtk_widget_show_all(dialog); reply = gnome_dialog_run(GNOME_DIALOG(dialog)); } --- NEW FILE: gstprefs.h --- void prefs_dialog (GtkWidget *widget, GstMediaPlay *mplay); --- NEW FILE: gststatusarea.c --- #include <config.h> #include "gststatusarea.h" static void gst_status_area_class_init (GstStatusAreaClass *klass); static void gst_status_area_init (GstStatusArea *status_area); static void gst_status_area_set_arg (GtkObject *object, GtkArg *arg, guint id); static void gst_status_area_get_arg (GtkObject *object, GtkArg *arg, guint id); static void gst_status_area_realize (GtkWidget *status_area); static gint gst_status_area_expose (GtkWidget *widget, GdkEventExpose *event); #define DEFAULT_HEIGHT 20 #define DEFAULT_EXPANDED_HEIGHT 100 /* signals and args */ enum { LAST_SIGNAL }; enum { ARG_0, }; static GtkDrawingArea *parent_class = NULL; //static guint gst_status_area_signals[LAST_SIGNAL] = { 0 }; GtkType gst_status_area_get_type (void) { static GtkType status_area_type = 0; if (!status_area_type) { static const GtkTypeInfo status_area_info = { "GstStatusArea", sizeof(GstStatusArea), sizeof(GstStatusAreaClass), (GtkClassInitFunc)gst_status_area_class_init, (GtkObjectInitFunc)gst_status_area_init, NULL, NULL, (GtkClassInitFunc)NULL, }; status_area_type = gtk_type_unique (gtk_widget_get_type (),&status_area_info); } return status_area_type; } static void gst_status_area_class_init (GstStatusAreaClass *klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; parent_class = gtk_type_class (gtk_widget_get_type ()); object_class = (GtkObjectClass*)klass; widget_class = (GtkWidgetClass*)klass; object_class->set_arg = gst_status_area_set_arg; object_class->get_arg = gst_status_area_get_arg; widget_class->realize = gst_status_area_realize; widget_class->expose_event = gst_status_area_expose; } static void gst_status_area_init (GstStatusArea *status_area) { GTK_WIDGET(status_area)->requisition.height = DEFAULT_HEIGHT; status_area->state = GST_STATUS_AREA_STATE_INIT; status_area->expanded = FALSE; } GstStatusArea * gst_status_area_new (void) { return GST_STATUS_AREA (gtk_type_new (GST_TYPE_STATUS_AREA)); } static void gst_status_area_realize (GtkWidget *widget) { GdkWindowAttr attributes; gint attributes_mask; GstStatusArea *status_area; g_return_if_fail (widget != NULL); g_return_if_fail(GST_IS_STATUS_AREA(widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); status_area = GST_STATUS_AREA(widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.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; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); } static gint gst_status_area_expose(GtkWidget *widget, GdkEventExpose *event) { GstStatusArea *status_area; guchar *statustext; g_return_val_if_fail (GST_IS_STATUS_AREA (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); status_area = GST_STATUS_AREA (widget); if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) { GdkFont *font; #ifdef USE_GLIB2 font = gtk_style_get_font(widget->style); #else /* !USE_GLIB2 */ font = widget->style->font; #endif /* !USE_GLIB2 */ gdk_draw_rectangle (widget->window, widget->style->black_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); if (status_area->expanded) { gint width; gdk_draw_line (widget->window, widget->style->dark_gc[0], 0, widget->allocation.height - 20, widget->allocation.width, widget->allocation.height - 20); width = gdk_string_width (font, "Show:"); gdk_draw_string (widget->window, font, widget->style->white_gc, 80-width, 15, "Show:"); width = gdk_string_width (font, "Clip:"); gdk_draw_string (widget->window, font, widget->style->white_gc, 80-width, 40, "Clip:"); width = gdk_string_width (font, "Author:"); gdk_draw_string (widget->window, font, widget->style->white_gc, 80-width, 55, "Author:"); width = gdk_string_width (font, "Copyright:"); gdk_draw_string (widget->window, font, widget->style->white_gc, 80-width, 70, "Copyright:"); gdk_draw_line (widget->window, widget->style->dark_gc[0], 0, widget->allocation.height - 80, widget->allocation.width, widget->allocation.height - 80); } switch (status_area->state) { case GST_STATUS_AREA_STATE_INIT: statustext = "Initializing"; break; case GST_STATUS_AREA_STATE_PLAYING: statustext = "Playing"; break; case GST_STATUS_AREA_STATE_PAUSED: statustext = "Paused"; break; case GST_STATUS_AREA_STATE_STOPPED: statustext = "Stopped"; break; default: statustext = ""; break; } gdk_draw_string (widget->window, font, widget->style->white_gc, 8, widget->allocation.height-5, statustext); if (status_area->playtime) { gint width = gdk_string_width (font, status_area->playtime); gdk_draw_string (widget->window, font, widget->style->white_gc, widget->allocation.width-width-20, widget->allocation.height-5, status_area->playtime); } } return FALSE; } void gst_status_area_set_state (GstStatusArea *area, GstStatusAreaState state) { g_return_if_fail(area != NULL); g_return_if_fail(GST_IS_STATUS_AREA(area)); area->state = state; if (GTK_WIDGET_VISIBLE(area)) gtk_widget_queue_draw(GTK_WIDGET(area)); } void gst_status_area_set_playtime (GstStatusArea *area, const guchar *time) { g_return_if_fail(area != NULL); g_return_if_fail(GST_IS_STATUS_AREA(area)); g_return_if_fail(time != NULL); if (area->playtime) g_free (area->playtime); area->playtime = g_strdup (time); if (GTK_WIDGET_VISIBLE(area)) gtk_widget_queue_draw(GTK_WIDGET(area)); } void gst_status_area_set_streamtype (GstStatusArea *area, const guchar *type) { } void cb_gst_toggle_extended (void) { //get pointer to status area //grab current extended status //reverse truth on that by gst_status_show_extended } void gst_status_area_show_extended (GstStatusArea *area, gboolean show) { area->expanded = show; if (show) { GTK_WIDGET(area)->requisition.height = DEFAULT_EXPANDED_HEIGHT; } else { GTK_WIDGET(area)->requisition.height = DEFAULT_HEIGHT; } gtk_widget_queue_resize (GTK_WIDGET (area)); } static void gst_status_area_set_arg(GtkObject *object, GtkArg *arg, guint id) { GstStatusArea *status_area; status_area = GST_STATUS_AREA(object); switch (id) { default: g_warning("GstStatusArea: unknown arg!"); break; } } static void gst_status_area_get_arg(GtkObject *object, GtkArg *arg, guint id) { GstStatusArea *status_area; status_area = GST_STATUS_AREA(object); switch (id) { default: arg->type = GTK_TYPE_INVALID; break; } } --- NEW FILE: gststatusarea.h --- #ifndef __GST_STATUS_AREA_H__ #define __GST_STATUS_AREA_H__ #include <gst/gst.h> #include <gtk/gtk.h> #define GST_TYPE_STATUS_AREA (gst_status_area_get_type ()) #define GST_STATUS_AREA(obj) (GTK_CHECK_CAST ((obj), GST_TYPE_STATUS_AREA, GstStatusArea)) #define GST_STATUS_AREA_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GST_TYPE_STATUS_AREA, GstStatusAreaClass)) #define GST_IS_STATUS_AREA(obj) (GTK_CHECK_TYPE ((obj), GST_TYPE_STATUS_AREA)) #define GST_IS_STATUS_AREA_CLASS(obj) (GTK_CHECK_CLASS_TYPE ((klass), GST_TYPE_STATUS_AREA)) typedef struct _GstStatusArea GstStatusArea; typedef struct _GstStatusAreaClass GstStatusAreaClass; typedef enum { GST_STATUS_AREA_STATE_INIT, GST_STATUS_AREA_STATE_PLAYING, GST_STATUS_AREA_STATE_PAUSED, GST_STATUS_AREA_STATE_STOPPED, } GstStatusAreaState; struct _GstStatusArea { GtkWidget parent; GstStatusAreaState state; guchar *playtime; gboolean expanded; }; struct _GstStatusAreaClass { GtkWidgetClass parent_class; }; GtkType gst_status_area_get_type (void); GstStatusArea* gst_status_area_new (void); void gst_status_area_set_state (GstStatusArea *area, GstStatusAreaState state); void gst_status_area_set_playtime (GstStatusArea *area, const guchar *time); void gst_status_area_set_streamtype (GstStatusArea *area, const guchar *type); void cb_gst_toggle_extended (void); void gst_status_area_show_extended (GstStatusArea *area, gboolean show); #endif /* __GST_STATUS_AREA_H__ */ --- NEW FILE: songinfo.c --- #include <config.h> #include "songinfo.h" SongInfo * songinfo_song_new (void) { SongInfo *info; info = g_new (SongInfo, 1); info->song = NULL; info->artist = NULL; info->filename = NULL; info->bitrate = 0; info->time = 0; info->size = 0; return info; } void songinfo_song_free (SongInfo *info) { if (info == NULL) return; if (info->song != NULL) g_free (info->song); if (info->artist != NULL) g_free (info->artist); if (info->filename != NULL) g_free (info->filename); g_free (info); } --- NEW FILE: songinfo.h --- #ifndef __SONGINFO_H__ #define __SONGINFO_H__ #include <gtk/gtk.h> typedef struct { gchar *song; gchar *artist; gchar *filename; gint bitrate; gint size; gint time; } SongInfo; SongInfo * songinfo_song_new (void); void songinfo_song_free (SongInfo *info); #endif /* __SONG_INFO_H__ */ |