[gnome-video-arcade] Add music clips to the Properties window.
- From: Matthew Barnes <mbarnes src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-video-arcade] Add music clips to the Properties window.
- Date: Mon, 15 Feb 2010 01:21:22 +0000 (UTC)
commit e476b11bc134f86e08a6cadae193c198ac94bfcf
Author: Matthew Barnes <mbarnes redhat com>
Date: Sun Feb 14 19:41:17 2010 -0500
Add music clips to the Properties window.
This adds an optional dependency on GStreamer. Music clips are streamed
in MP3 format from http://www.arcade-history.com/. Music clips are not
yet available for all games, but the collection appears to be growing.
NEWS | 10 +
README | 30 +-
configure.ac | 19 +
data/gnome-video-arcade.builder | 146 +++++--
data/gnome-video-arcade.schemas | 19 +-
docs/reference/Makefile.am | 3 +
docs/reference/gnome-video-arcade-docs.sgml | 1 +
docs/reference/gnome-video-arcade-sections.txt | 32 ++-
docs/reference/gnome-video-arcade.types | 2 +
docs/reference/tmpl/gva-history.sgml | 9 +
docs/reference/tmpl/gva-music-button.sgml | 100 ++++
docs/reference/tmpl/gva-preferences.sgml | 16 +
docs/reference/tmpl/gva-process.sgml | 2 +-
docs/reference/tmpl/gva-properties.sgml | 3 +-
docs/reference/tmpl/gva-ui.sgml | 7 +
docs/reference/tmpl/gva-util.sgml | 1 +
maint/Makefile.am | 5 +-
maint/gva.xml | 7 +
po/POTFILES.in | 1 +
src/Makefile.am | 7 +-
src/gva-common.h | 10 +-
src/gva-db.c | 2 +-
src/gva-history.c | 116 +++--
src/gva-history.h | 1 +
src/gva-input-file.c | 12 +-
src/gva-mame-process.c | 22 +-
src/gva-music-button.c | 646 ++++++++++++++++++++++++
src/gva-music-button.h | 91 ++++
src/gva-preferences.c | 97 +++-
src/gva-preferences.h | 2 +
src/gva-process.c | 25 +-
src/gva-properties.c | 67 +++-
src/gva-properties.h | 3 +-
src/gva-ui.c | 29 +
src/gva-ui.h | 9 +
src/gva-util.c | 31 ++-
src/gva-util.h | 13 +-
src/main.c | 8 +
38 files changed, 1456 insertions(+), 148 deletions(-)
---
diff --git a/NEWS b/NEWS
index f9e8eff..4817f5e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,13 @@
+GNOME Video Arcade 0.7.0
+========================
+
+ Released ???, 2010
+
+ What's New
+ ----------
+ * In the Properties window you can now listen to music clips of
+ the selected game. Not all games have music clips available.
+
GNOME Video Arcade 0.6.8
========================
diff --git a/README b/README
index ecaf53c..c9a9eaf 100644
--- a/README
+++ b/README
@@ -46,7 +46,7 @@ installed prior to compiling the source code:
varies by distribution, but it should be something similar to
gtk2-devel (Fedora) or libgtk2.0-dev (Debian/Ubuntu).
- - Header files for GConf version 2.0 (or higher)
+ - Header files for GConf version 2.0 (or higher).
GNOME Video Arcade uses GConf to remember preferences, favorites
and other miscellaneous user data. The GConf header files should
@@ -79,6 +79,18 @@ installed prior to compiling the source code:
you can configure GNOME Video Arcade to not link against it.
See the Installation section to find out how.
+ - Header files for GStreamer version 0.10 (or higher). (optional)
+
+ The GStreamer header files should be available from your
+ GNU/Linux distribution as a "development" package. The exact
+ package name varies by distribution, but it should be something
+ similar to gstreamer-devel (Fedora) or libgstreamer0.10-dev
+ (Debian/Ubuntu).
+
+ GNOME Video Arcade uses GStreamer to stream video game music
+ clips in the Properties window. The music clips are streamed
+ from http://www.arcade-history.com.
+
- Header files for libgnomeui version 2.14 (or higher). (optional)
The libgnomeui header files should be available from your
@@ -142,11 +154,11 @@ including GNOME Video Arcade. This section supplements the INSTALL
file with information specific to GNOME Video Arcade.
These instructions are written specifically for GNOME Video Arcade
-version 0.6.7 and may change in forthcoming releases.
+version 0.7.0 and may change in forthcoming releases.
The standard installation procedure looks like this:
- $ cd /path/to/gnome-video-arcade-0.6.7
+ $ cd /path/to/gnome-video-arcade-0.7.0
$ ./configure
$ make
$ su -c "make install"
@@ -193,11 +205,13 @@ installed, the documentation can be viewed through Devhelp.
The --with-gnome and --without-gnome configure options tell "make"
whether to link against high-level GNOME libraries like libgnomeui.
-Similarly, the --with-wnck and --without-wnck configure options
-tell "make" whether to link against libwnck, and the --with-dbus
-and --without-dbus configure options tell "make" whether to link
-against D-Bus. See the previous section for details on what these
-libraries are used for.
+Similar "with"/"without" options are available for other optional
+libraries including D-Bus, GStreamer and libwnck. See the previous
+section for details on what these libraries are used for.
+
+For a complete list of configure options, run:
+
+ $ ./configure --help
UPDATE: --with-gnome is now ignored if GTK+ >= 2.14 is detected.
diff --git a/configure.ac b/configure.ac
index f7ec091..c5e792c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,6 +88,24 @@ fi
AC_SUBST(GNOME_CFLAGS)
AC_SUBST(GNOME_LIBS)
+# --with-gstreamer=[yes|no]
+AC_ARG_WITH([gstreamer],
+ [AC_HELP_STRING([--with-gstreamer],
+ [use GStreamer to stream music [default=yes]])],
+ with_gstreamer="$withval", with_gstreamer="yes")
+if test "$with_gstreamer" = "yes"; then
+GSTREAMER_MODULES="gstreamer-0.10"
+PKG_CHECK_MODULES(GSTREAMER, $GSTREAMER_MODULES)
+AC_DEFINE_UNQUOTED(HAVE_GSTREAMER, 1,
+ [Define to 1 if you are using GStreamer])
+else
+GSTREAMER_CFLAGS=
+GSTREAMER_LIBS=
+fi
+AM_CONDITIONAL(HAVE_GSTREAMER, test $with_gstreamer = yes)
+AC_SUBST(GSTREAMER_CFLAGS)
+AC_SUBST(GSTREAMER_LIBS)
+
# --with-wnck=[yes|no]
AC_ARG_WITH([wnck],
[AC_HELP_STRING([--with-wnck],
@@ -235,6 +253,7 @@ echo " Category File : $with_category"
echo " History File : $with_history"
echo " NPlayers File : $with_nplayers"
echo " Use D-Bus : $with_dbus"
+echo " Use GStreamer : $with_gstreamer"
echo " Use libgnomeui : $with_gnome"
echo " Use libwnck : $with_wnck"
echo
diff --git a/data/gnome-video-arcade.builder b/data/gnome-video-arcade.builder
index f79a8ec..6904b8e 100644
--- a/data/gnome-video-arcade.builder
+++ b/data/gnome-video-arcade.builder
@@ -1,6 +1,7 @@
<?xml version="1.0"?>
<interface>
<!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-requires gva 0.0 -->
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkWindow" id="main-window">
<property name="title" translatable="yes">GNOME Video Arcade</property>
@@ -63,25 +64,28 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="tooltip-text" translatable="yes">Show my search results</property>
+ <property name="tooltip_text" translatable="yes">Show my search results</property>
</object>
<packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
</child>
<child>
<object class="GvaMuteButton" id="main-mute-button">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_markup">In-game sound is enabled</property>
<property name="tooltip_text">In-game sound is enabled</property>
- <property name="relief">GTK_RELIEF_NONE</property>
- <child>
- <placeholder/>
- </child>
+ <property name="relief">none</property>
</object>
<packing>
<property name="expand">False</property>
@@ -93,6 +97,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
@@ -600,6 +605,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
@@ -686,6 +692,7 @@
<property name="default_height">400</property>
<property name="destroy_with_parent">True</property>
<property name="transient_for">main-window</property>
+ <signal name="hide" handler="gva_properties_hide_cb"/>
<signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
<signal name="show" handler="gva_properties_show_cb"/>
<child>
@@ -702,7 +709,7 @@
<property name="n_columns">2</property>
<property name="column_spacing">12</property>
<child>
- <object class="GtkHBox" id="properties-hbox">
+ <object class="GtkHBox" id="properties-upper-hbox">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">3</property>
@@ -790,7 +797,6 @@ Manufacturer, Year</property>
<child>
<object class="GtkNotebook" id="properties-history-notebook">
<property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="show_tabs">False</property>
<property name="show_border">False</property>
@@ -842,7 +848,6 @@ Manufacturer, Year</property>
<child>
<object class="GtkNotebook" id="properties-gallery-notebook">
<property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="show_tabs">False</property>
<property name="show_border">False</property>
@@ -956,7 +961,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-imperfect-color-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ The colors aren't 100% accurate.</property>
+ <property name="label" translatable="yes">• The colors aren't 100% accurate.</property>
<property name="ellipsize">end</property>
</object>
<packing>
@@ -967,7 +972,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-preliminary-color-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ The colors are completely wrong.</property>
+ <property name="label" translatable="yes">• The colors are completely wrong.</property>
<property name="ellipsize">end</property>
</object>
<packing>
@@ -978,7 +983,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-imperfect-graphic-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ The video emulation isn't 100% accurate.</property>
+ <property name="label" translatable="yes">• The video emulation isn't 100% accurate.</property>
<property name="ellipsize">end</property>
</object>
<packing>
@@ -989,7 +994,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-imperfect-sound-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ The sound emulation isn't 100% accurate.</property>
+ <property name="label" translatable="yes">• The sound emulation isn't 100% accurate.</property>
<property name="ellipsize">end</property>
</object>
<packing>
@@ -1000,7 +1005,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-preliminary-sound-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ The game lacks sound.</property>
+ <property name="label" translatable="yes">• The game lacks sound.</property>
<property name="ellipsize">end</property>
</object>
<packing>
@@ -1011,7 +1016,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-preliminary-cocktail-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ Screen flipping in cocktail mode is not supported.</property>
+ <property name="label" translatable="yes">• Screen flipping in cocktail mode is not supported.</property>
<property name="ellipsize">end</property>
</object>
<packing>
@@ -1022,7 +1027,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-preliminary-emulation-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ <b>THIS GAME DOESN'T WORK.</b></property>
+ <property name="label" translatable="yes">• <b>THIS GAME DOESN'T WORK.</b></property>
<property name="use_markup">True</property>
</object>
<packing>
@@ -1035,7 +1040,7 @@ Manufacturer, Year</property>
<object class="GtkLabel" id="properties-preliminary-protection-label">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">â?¢ The game has protection which isn't fully emulated.</property>
+ <property name="label" translatable="yes">• The game has protection which isn't fully emulated.</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1493,29 +1498,106 @@ Manufacturer, Year</property>
</packing>
</child>
<child>
- <object class="GtkHButtonBox" id="properties-button-box">
+ <object class="GtkHBox" id="properties-lower-hbox">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="layout_style">end</property>
+ <property name="spacing">12</property>
<child>
- <object class="GtkButton" id="properties-close-button">
- <property name="label">gtk-close</property>
+ <object class="GtkTable" id="properties-music-table">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="is_focus">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="receives_default">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="tooltip_text" translatable="yes">Close this window</property>
- <property name="use_stock">True</property>
- <signal name="clicked" handler="gva_properties_close_clicked_cb" object="properties-window"/>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkAlignment" id="properties-music-alignment">
+ <property name="visible">True</property>
+ <property name="yalign">1</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GvaMusicButton" id="properties-music-button">
+ <property name="width_request">64</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Play a music clip</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="properties-music-status">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><small></small></property>
+ <property name="use_markup">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="properties-music-auto-play">
+ <property name="label">(auto-play) GtkUIManager supplies the label</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="properties-button-box-alignment">
+ <property name="visible">True</property>
+ <property name="yalign">1</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkHButtonBox" id="properties-button-box">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="properties-close-button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="tooltip_text" translatable="yes">Close this window</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="gtk_widget_hide" object="properties-window"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">0</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
diff --git a/data/gnome-video-arcade.schemas b/data/gnome-video-arcade.schemas
index 2e34d72..062f928 100644
--- a/data/gnome-video-arcade.schemas
+++ b/data/gnome-video-arcade.schemas
@@ -16,6 +16,23 @@
</schema>
<schema>
+ <applyto>/apps/gnome-video-arcade/auto-play</applyto>
+ <key>/schemas/apps/gnome-video-arcade/auto-play</key>
+ <owner>gnome-video-arcade</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Auto-play music clip</short>
+ <long>Enable automatic playing of in-game music clips.
+ If true, and a music clip is available for the selected game,
+ the clip will automatically begin playing when the user opens the
+ Properties window or when the user selects a different game while
+ the Properties window is visible. Music clips are streamed from
+ http://www.arcade-history.com/.</long>
+ </locale>
+ </schema>
+
+ <schema>
<applyto>/apps/gnome-video-arcade/auto-save</applyto>
<key>/schemas/apps/gnome-video-arcade/auto-save</key>
<owner>gnome-video-arcade</owner>
@@ -177,7 +194,7 @@
<schema>
<applyto>/apps/gnome-video-arcade/sound-muted</applyto>
- <key>/apps/gnome-video-arcade/sound-muted</key>
+ <key>/schemas/apps/gnome-video-arcade/sound-muted</key>
<owner>gnome-video-arcade</owner>
<type>bool</type>
<default>false</default>
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index ddd9a2e..58f84df 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -81,6 +81,7 @@ INCLUDES= \
$(GCONF_CFLAGS) \
$(GLADE_CFLAGS) \
$(GNOME_CFLAGS) \
+ $(GSTREAMER_CFLAGS) \
$(SQLITE_CFLAGS) \
$(WNCK_CFLAGS)
@@ -105,6 +106,7 @@ GTKDOC_LIBS= \
$(top_builddir)/src/gva-main.o \
$(top_builddir)/src/gva-mame-common.o \
$(top_builddir)/src/gva-mame-process.o \
+ $(top_builddir)/src/gva-music-button.o \
$(top_builddir)/src/gva-mute-button.o \
$(top_builddir)/src/gva-nplayers.o \
$(top_builddir)/src/gva-play-back.o \
@@ -125,6 +127,7 @@ GTKDOC_LIBS= \
$(GCONF_LIBS) \
$(GLADE_LIBS) \
$(GNOME_LIBS) \
+ $(GSTREAMER_LIBS) \
$(SQLITE_LIBS) \
$(WNCK_LIBS)
diff --git a/docs/reference/gnome-video-arcade-docs.sgml b/docs/reference/gnome-video-arcade-docs.sgml
index e24ca55..f0503c8 100644
--- a/docs/reference/gnome-video-arcade-docs.sgml
+++ b/docs/reference/gnome-video-arcade-docs.sgml
@@ -45,6 +45,7 @@
<xi:include href="xml/gva-input-file.xml"/>
<xi:include href="xml/gva-link-button.xml"/>
<xi:include href="xml/gva-mame-process.xml"/>
+ <xi:include href="xml/gva-music-button.xml"/>
<xi:include href="xml/gva-mute-button.xml"/>
<xi:include href="xml/gva-process.xml"/>
</chapter>
diff --git a/docs/reference/gnome-video-arcade-sections.txt b/docs/reference/gnome-video-arcade-sections.txt
index 4847410..31b63ad 100644
--- a/docs/reference/gnome-video-arcade-sections.txt
+++ b/docs/reference/gnome-video-arcade-sections.txt
@@ -176,6 +176,7 @@ gva_link_button_get_type
<FILE>gva-history</FILE>
gva_history_init
gva_history_lookup
+gva_history_lookup_id
</SECTION>
<SECTION>
@@ -263,6 +264,29 @@ gva_mame_process_get_type
</SECTION>
<SECTION>
+<FILE>gva-music-button</FILE>
+<TITLE>GvaMusicButton</TITLE>
+GvaMusicButton
+gva_music_button_new
+gva_music_button_play
+gva_music_button_pause
+gva_music_button_get_game
+gva_music_button_set_game
+gva_music_button_get_status
+<SUBSECTION Standard>
+GVA_MUSIC_BUTTON
+GVA_IS_MUSIC_BUTTON
+GVA_TYPE_MUSIC_BUTTON
+GVA_MUSIC_BUTTON_CLASS
+GVA_IS_MUSIC_BUTTON_CLASS
+GVA_MUSIC_BUTTON_GET_CLASS
+GvaMusicButtonClass
+<SUBSECTION Private>
+GvaMusicButtonPrivate
+gva_music_button_get_type
+</SECTION>
+
+<SECTION>
<FILE>gva-mute-button</FILE>
<TITLE>GvaMuteButton</TITLE>
GvaMuteButton
@@ -303,6 +327,8 @@ gva_play_back_window_hide_cb
<SECTION>
<FILE>gva-preferences</FILE>
gva_preferences_init
+gva_preferences_get_auto_play
+gva_preferences_set_auto_play
gva_preferences_get_auto_save
gva_preferences_set_auto_save
gva_preferences_get_full_screen
@@ -350,7 +376,7 @@ gva_process_get_type
<FILE>gva-properties</FILE>
gva_properties_init
gva_properties_show_game
-gva_properties_close_clicked_cb
+gva_properties_hide_cb
gva_properties_show_cb
</SECTION>
@@ -386,6 +412,7 @@ gva_time_get_type
<SECTION>
<FILE>gva-ui</FILE>
GVA_ACTION_ABOUT
+GVA_ACTION_AUTO_PLAY
GVA_ACTION_AUTO_SAVE
GVA_ACTION_CONTENTS
GVA_ACTION_FULL_SCREEN
@@ -452,6 +479,9 @@ GVA_WIDGET_PROPERTIES_HISTORY_TEXT_VIEW
GVA_WIDGET_PROPERTIES_IMPERFECT_COLOR_LABEL
GVA_WIDGET_PROPERTIES_IMPERFECT_GRAPHIC_LABEL
GVA_WIDGET_PROPERTIES_IMPERFECT_SOUND_LABEL
+GVA_WIDGET_PROPERTIES_MUSIC_AUTO_PLAY
+GVA_WIDGET_PROPERTIES_MUSIC_BUTTON
+GVA_WIDGET_PROPERTIES_MUSIC_STATUS
GVA_WIDGET_PROPERTIES_NOTEBOOK
GVA_WIDGET_PROPERTIES_ORIGINAL_LINKS
GVA_WIDGET_PROPERTIES_ORIGINAL_VBOX
diff --git a/docs/reference/gnome-video-arcade.types b/docs/reference/gnome-video-arcade.types
index 1a62282..8811992 100644
--- a/docs/reference/gnome-video-arcade.types
+++ b/docs/reference/gnome-video-arcade.types
@@ -4,6 +4,7 @@
#include <gva-input-file.h>
#include <gva-link-button.h>
#include <gva-mame-process.h>
+#include <gva-music-button.h>
#include <gva-mute-button.h>
#include <gva-process.h>
#include <gva-time.h>
@@ -14,6 +15,7 @@ gva_game_store_get_type
gva_input_file_get_type
gva_link_button_get_type
gva_mame_process_get_type
+gva_music_button_get_type
gva_mute_button_get_type
gva_process_get_type
gva_time_get_type
diff --git a/docs/reference/tmpl/gva-history.sgml b/docs/reference/tmpl/gva-history.sgml
index b0b73f0..0e2839c 100644
--- a/docs/reference/tmpl/gva-history.sgml
+++ b/docs/reference/tmpl/gva-history.sgml
@@ -36,3 +36,12 @@
@Returns:
+<!-- ##### FUNCTION gva_history_lookup_id ##### -->
+<para>
+
+</para>
+
+ game:
+ Returns:
+
+
diff --git a/docs/reference/tmpl/gva-music-button.sgml b/docs/reference/tmpl/gva-music-button.sgml
new file mode 100644
index 0000000..bfad33c
--- /dev/null
+++ b/docs/reference/tmpl/gva-music-button.sgml
@@ -0,0 +1,100 @@
+<!-- ##### SECTION Title ##### -->
+GvaMusicButton
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GvaMusicButton ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL GvaMusicButton::pause ##### -->
+<para>
+
+</para>
+
+ gvamusicbutton: the object which received the signal.
+
+<!-- ##### SIGNAL GvaMusicButton::play ##### -->
+<para>
+
+</para>
+
+ gvamusicbutton: the object which received the signal.
+
+<!-- ##### ARG GvaMusicButton:game ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GvaMusicButton:status ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gva_music_button_new ##### -->
+<para>
+
+</para>
+
+ Returns:
+
+
+<!-- ##### FUNCTION gva_music_button_play ##### -->
+<para>
+
+</para>
+
+ music_button:
+
+
+<!-- ##### FUNCTION gva_music_button_pause ##### -->
+<para>
+
+</para>
+
+ music_button:
+
+
+<!-- ##### FUNCTION gva_music_button_get_game ##### -->
+<para>
+
+</para>
+
+ music_button:
+ Returns:
+
+
+<!-- ##### FUNCTION gva_music_button_set_game ##### -->
+<para>
+
+</para>
+
+ music_button:
+ game:
+
+
+<!-- ##### FUNCTION gva_music_button_get_status ##### -->
+<para>
+
+</para>
+
+ music_button:
+ Returns:
+
+
diff --git a/docs/reference/tmpl/gva-preferences.sgml b/docs/reference/tmpl/gva-preferences.sgml
index 2f86ebe..9a0c0d2 100644
--- a/docs/reference/tmpl/gva-preferences.sgml
+++ b/docs/reference/tmpl/gva-preferences.sgml
@@ -24,6 +24,22 @@
+<!-- ##### FUNCTION gva_preferences_get_auto_play ##### -->
+<para>
+
+</para>
+
+ Returns:
+
+
+<!-- ##### FUNCTION gva_preferences_set_auto_play ##### -->
+<para>
+
+</para>
+
+ auto_play:
+
+
<!-- ##### FUNCTION gva_preferences_get_auto_save ##### -->
<para>
diff --git a/docs/reference/tmpl/gva-process.sgml b/docs/reference/tmpl/gva-process.sgml
index b9fbfc1..b54af41 100644
--- a/docs/reference/tmpl/gva-process.sgml
+++ b/docs/reference/tmpl/gva-process.sgml
@@ -1,5 +1,5 @@
<!-- ##### SECTION Title ##### -->
-
+GvaProcess
<!-- ##### SECTION Short_Description ##### -->
diff --git a/docs/reference/tmpl/gva-properties.sgml b/docs/reference/tmpl/gva-properties.sgml
index f8213c6..b356e69 100644
--- a/docs/reference/tmpl/gva-properties.sgml
+++ b/docs/reference/tmpl/gva-properties.sgml
@@ -32,13 +32,12 @@
@game:
-<!-- ##### FUNCTION gva_properties_close_clicked_cb ##### -->
+<!-- ##### FUNCTION gva_properties_hide_cb ##### -->
<para>
</para>
@window:
- button:
<!-- ##### FUNCTION gva_properties_show_cb ##### -->
diff --git a/docs/reference/tmpl/gva-ui.sgml b/docs/reference/tmpl/gva-ui.sgml
index 8d1fa1f..35a3be4 100644
--- a/docs/reference/tmpl/gva-ui.sgml
+++ b/docs/reference/tmpl/gva-ui.sgml
@@ -24,6 +24,13 @@
+<!-- ##### MACRO GVA_ACTION_AUTO_PLAY ##### -->
+<para>
+
+</para>
+
+
+
<!-- ##### MACRO GVA_ACTION_AUTO_SAVE ##### -->
<para>
diff --git a/docs/reference/tmpl/gva-util.sgml b/docs/reference/tmpl/gva-util.sgml
index de07e35..a7d447d 100644
--- a/docs/reference/tmpl/gva-util.sgml
+++ b/docs/reference/tmpl/gva-util.sgml
@@ -53,6 +53,7 @@
@GVA_DEBUG_SQL:
@GVA_DEBUG_IO:
@GVA_DEBUG_INP:
+ GVA_DEBUG_GST:
<!-- ##### FUNCTION gva_get_last_version ##### -->
<para>
diff --git a/maint/Makefile.am b/maint/Makefile.am
index ff7a80f..d573cd2 100644
--- a/maint/Makefile.am
+++ b/maint/Makefile.am
@@ -14,11 +14,12 @@ gladegvadir = `$(PKG_CONFIG) --variable=moduledir gladeui-1.0`
libgladegva_la_CFLAGS = \
@GLIB_CFLAGS@ @GTK_CFLAGS@ \
- @GCONF_CFLAGS@
+ @GCONF_CFLAGS@ @GSTREAMER_CFLAGS@
libgladegva_la_SOURCES = \
$(top_srcdir)/src/gva-column-manager.c \
$(top_srcdir)/src/gva-link-button.c \
+ $(top_srcdir)/src/gva-music-button.c \
$(top_srcdir)/src/gva-mute-button.c
libgladegva_la_LDFLAGS = \
@@ -26,7 +27,7 @@ libgladegva_la_LDFLAGS = \
libgladegva_la_LIBADD = \
@GLIB_LIBS@ @GTK_LIBS@ \
- @GCONF_LIBS@
+ @GCONF_LIBS@ @GSTREAMER_LIBS@
EXTRA_DIST = \
$(gladecatalog_DATA) \
diff --git a/maint/gva.xml b/maint/gva.xml
index d79d652..14d46ba 100644
--- a/maint/gva.xml
+++ b/maint/gva.xml
@@ -10,6 +10,12 @@
<glade-widget-class name="GvaLinkButton" generic-name="link-button" title="Link Button"/>
+ <glade-widget-class name="GvaMusicButton" generic-name="music-button" title="Music Button">
+ <properties>
+ <property id="game"/>
+ </properties>
+ </glade-widget-class>
+
<glade-widget-class name="GvaMuteButton" generic-name="mute-button" title="Mute Button">
<properties>
<property id="muted"/>
@@ -21,6 +27,7 @@
<glade-widget-group name="gva-widgets" title="GNOME Video Arcade">
<glade-widget-class-ref name="GvaColumnManager"/>
<glade-widget-class-ref name="GvaLinkButton"/>
+ <glade-widget-class-ref name="GvaMusicButton"/>
<glade-widget-class-ref name="GvaMuteButton"/>
</glade-widget-group>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 765e4b7..5843b27 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -14,6 +14,7 @@ src/gva-mame-common.c
src/gva-mame-process.c
src/gva-mame-sdlmame.c
src/gva-mame-xmame.c
+src/gva-music-button.c
src/gva-mute-button.c
src/gva-nplayers.c
src/gva-play-back.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 4e8b72c..fae9659 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,7 @@ AM_CFLAGS = \
-Wall \
@DBUS_CFLAGS@ @GLIB_CFLAGS@ @GTK_CFLAGS@ \
@GIT_CFLAGS@ @GCONF_CFLAGS@ @GNOME_CFLAGS@ \
- @SQLITE_CFLAGS@ @WNCK_CFLAGS@
+ @GSTREAMER_CFLAGS@ @SQLITE_CFLAGS@ @WNCK_CFLAGS@
# The DATADIR, LIBDIR, PREFIX, and SYSCONFDIR definitions
# are only needed for libgnome. GLib handles it better.
@@ -63,6 +63,8 @@ gnome_video_arcade_SOURCES = \
gva-mame-process.c \
gva-mame-process.h \
gva-mame.h \
+ gva-music-button.c \
+ gva-music-button.h \
gva-mute-button.c \
gva-mute-button.h \
gva-nplayers.c \
@@ -95,7 +97,8 @@ EXTRA_gnome_video_arcade_SOURCES = \
gnome_video_arcade_LDADD = \
@DBUS_LIBS@ @GLIB_LIBS@ @GTK_LIBS@ \
@GIT_LIBS@ @GCONF_LIBS@ @GNOME_LIBS@ \
- @MAME_BACKEND@ @SQLITE_LIBS@ @WNCK_LIBS@
+ @GSTREAMER_LIBS@ @MAME_BACKEND@ \
+ @SQLITE_LIBS@ @WNCK_LIBS@
gnome_video_arcade_DEPENDENCIES = \
@MAME_BACKEND@
diff --git a/src/gva-common.h b/src/gva-common.h
index 44b7829..9b67cf6 100644
--- a/src/gva-common.h
+++ b/src/gva-common.h
@@ -19,6 +19,8 @@
/**
* SECTION: gva-common
* @short_description: Common Definitions
+ *
+ * Common symbols used throughout GNOME Video Arcade.
**/
#ifndef GVA_COMMON_H
@@ -28,10 +30,13 @@
#include "config.h"
#endif /* HAVE_CONFIG_H */
-#include <glib.h>
+#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
-#include <gtk/gtk.h>
+
+#if HAVE_GSTREAMER
+#include <gst/gst.h>
+#endif
#include <sqlite3.h>
#include <gconf/gconf-client.h>
@@ -39,6 +44,7 @@
#define GVA_GCONF_PREFIX "/apps/" PACKAGE
#define GVA_GCONF_ALL_COLUMNS_KEY GVA_GCONF_PREFIX "/all-columns"
+#define GVA_GCONF_AUTO_PLAY_KEY GVA_GCONF_PREFIX "/auto-play"
#define GVA_GCONF_AUTO_SAVE_KEY GVA_GCONF_PREFIX "/auto-save"
#define GVA_GCONF_COLUMNS_KEY GVA_GCONF_PREFIX "/columns"
#define GVA_GCONF_FAVORITES_KEY GVA_GCONF_PREFIX "/favorites"
diff --git a/src/gva-db.c b/src/gva-db.c
index db17172..a4c941a 100644
--- a/src/gva-db.c
+++ b/src/gva-db.c
@@ -1641,7 +1641,7 @@ db_function_match (sqlite3_context *context,
static void
db_trace_cb (gpointer unused, const gchar *message)
{
- g_debug ("%s", message);
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_SQL, "%s", message);
}
/**
diff --git a/src/gva-history.c b/src/gva-history.c
index 8035c03..28240ff 100644
--- a/src/gva-history.c
+++ b/src/gva-history.c
@@ -18,10 +18,21 @@
#include "gva-history.h"
+#include <stdlib.h>
+
#include "gva-error.h"
-static GArray *history_file_offset_array = NULL;
-static GHashTable *history_file_offset_table = NULL;
+#define BASE_URI "http://www.arcade-history.com/"
+
+typedef struct _HistoryEntry HistoryEntry;
+
+struct _HistoryEntry {
+ guint id;
+ goffset offset;
+};
+
+static GPtrArray *history_file_array = NULL;
+static GHashTable *history_file_table = NULL;
static GIOChannel *
history_file_open (GError **error)
@@ -48,30 +59,32 @@ history_file_open (GError **error)
}
static void
-history_file_mark (const gchar *line, gint64 offset)
+history_process_info (HistoryEntry *entry,
+ const gchar *line)
{
gchar **games;
guint length, ii;
- g_array_append_val (history_file_offset_array, offset);
-
- /* Skip "$info=" prefix. */
- games = g_strsplit (line + 6, ",", -1);
+ games = g_strsplit (line, ",", -1);
length = g_strv_length (games);
for (ii = 0; ii < length; ii++)
- {
- if (*g_strstrip (games[ii]) == '\0')
- continue;
-
- g_hash_table_insert (
- history_file_offset_table, g_strdup (games[ii]),
- GUINT_TO_POINTER (history_file_offset_array->len - 1));
- }
+ if (*g_strstrip (games[ii]) != '\0')
+ g_hash_table_insert (
+ history_file_table,
+ g_strdup (games[ii]), entry);
g_strfreev (games);
}
+static void
+history_process_link (HistoryEntry *entry,
+ const gchar *line)
+{
+ if ((line = strstr (line, "&id=")) != NULL)
+ entry->id = (guint) strtol (line + 4, NULL, 10);
+}
+
/**
* gva_history_init:
* @error: return location for a #GError, or %NULL
@@ -86,26 +99,26 @@ history_file_mark (const gchar *line, gint64 offset)
gboolean
gva_history_init (GError **error)
{
+ HistoryEntry *entry;
GIOChannel *channel;
GIOStatus status;
GString *buffer;
- gint64 offset = 0;
+ goffset offset = 0;
- g_return_val_if_fail (history_file_offset_array == NULL, FALSE);
- g_return_val_if_fail (history_file_offset_table == NULL, FALSE);
-
- channel = history_file_open (error);
- if (channel == NULL)
- return FALSE;
+ g_return_val_if_fail (history_file_array == NULL, FALSE);
+ g_return_val_if_fail (history_file_table == NULL, FALSE);
- history_file_offset_array =
- g_array_new (FALSE, FALSE, sizeof (gint64));
+ history_file_array = g_ptr_array_new ();
- history_file_offset_table = g_hash_table_new_full (
+ history_file_table = g_hash_table_new_full (
g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) NULL);
+ channel = history_file_open (error);
+ if (channel == NULL)
+ return FALSE;
+
buffer = g_string_sized_new (1024);
while (TRUE)
@@ -121,7 +134,19 @@ gva_history_init (GError **error)
offset += buffer->len;
if (g_str_has_prefix (buffer->str, "$info="))
- history_file_mark (buffer->str, offset);
+ {
+ entry = g_slice_new0 (HistoryEntry);
+ g_ptr_array_add (history_file_array, entry);
+ history_process_info (entry, buffer->str + 6);
+ }
+ else if (g_str_has_prefix (buffer->str, "$<a"))
+ {
+ history_process_link (entry, buffer->str + 1);
+ }
+ else if (g_str_has_prefix (buffer->str, "$bio"))
+ {
+ entry->offset = offset;
+ }
}
g_string_free (buffer, TRUE);
@@ -144,18 +169,16 @@ gchar *
gva_history_lookup (const gchar *game,
GError **error)
{
+ HistoryEntry *entry;
GIOChannel *channel;
GIOStatus status;
GString *buffer;
GString *history;
gboolean free_history;
- gpointer key, value;
- gint64 offset;
- guint index;
g_return_val_if_fail (game != NULL, NULL);
- g_return_val_if_fail (history_file_offset_array != NULL, NULL);
- g_return_val_if_fail (history_file_offset_table != NULL, NULL);
+ g_return_val_if_fail (history_file_array != NULL, NULL);
+ g_return_val_if_fail (history_file_table != NULL, NULL);
channel = history_file_open (error);
if (channel == NULL)
@@ -165,18 +188,14 @@ gva_history_lookup (const gchar *game,
history = g_string_sized_new (8096);
free_history = TRUE; /* assume failure */
- if (!g_hash_table_lookup_extended (
- history_file_offset_table, game, &key, &value))
+ entry = g_hash_table_lookup (history_file_table, game);
+ if (entry == NULL || entry->offset == 0)
goto exit;
- index = GPOINTER_TO_UINT (value);
- g_assert (index < history_file_offset_array->len);
- offset = g_array_index (history_file_offset_array, gint64, index);
-
status = G_IO_STATUS_AGAIN;
while (status == G_IO_STATUS_AGAIN)
status = g_io_channel_seek_position (
- channel, offset, G_SEEK_SET, error);
+ channel, entry->offset, G_SEEK_SET, error);
if (status == G_IO_STATUS_ERROR)
goto exit;
@@ -230,3 +249,24 @@ exit:
return g_string_free (history, free_history);
}
+
+/**
+ * gva_history_lookup_id:
+ * @game: the name of a game
+ *
+ * Returns the numeric ID for @game at http://www.arcade-history.com/.
+ * This is used to help locate game-specific resources on the website.
+ *
+ * Returns: ID for @game, or zero if unknown
+ **/
+guint
+gva_history_lookup_id (const gchar *game)
+{
+ HistoryEntry *entry;
+
+ g_return_val_if_fail (game != NULL, 0);
+
+ entry = g_hash_table_lookup (history_file_table, game);
+
+ return (entry != NULL) ? entry->id : 0;
+}
diff --git a/src/gva-history.h b/src/gva-history.h
index d7a8be4..1dd3596 100644
--- a/src/gva-history.h
+++ b/src/gva-history.h
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
gboolean gva_history_init (GError **error);
gchar * gva_history_lookup (const gchar *game,
GError **error);
+guint gva_history_lookup_id (const gchar *game);
G_END_DECLS
diff --git a/src/gva-input-file.c b/src/gva-input-file.c
index e8c14b6..cd63cc7 100644
--- a/src/gva-input-file.c
+++ b/src/gva-input-file.c
@@ -130,12 +130,12 @@ input_file_dump_header (GvaInputFile *input_file)
inpname = g_strdelimit (g_path_get_basename (filename), ".", '\0');
- g_debug ("Input file: %s", inpname);
- g_debug ("Game: %s", game);
- g_debug ("%s", format);
- g_debug ("Created %s", ctime (×tamp));
- g_debug ("Recorded using %s", origin);
- g_debug ("--");
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_INP, "Input file: %s", inpname);
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_INP, "Game: %s", game);
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_INP, "%s", format);
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_INP, "Created %s", ctime (×tamp));
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_INP, "Recorded using %s", origin);
+ g_log (G_LOG_DOMAIN, GVA_DEBUG_INP, "--");
g_free (inpname);
}
diff --git a/src/gva-mame-process.c b/src/gva-mame-process.c
index bf938e0..a250fa0 100644
--- a/src/gva-mame-process.c
+++ b/src/gva-mame-process.c
@@ -82,14 +82,12 @@ mame_process_stderr_read_line (GvaProcess *process)
static void
mame_process_exited (GvaProcess *process, gint status)
{
- if (WIFEXITED (status) && (gva_get_debug_flags () & GVA_DEBUG_MAME))
- {
- GPid pid;
-
- status = WEXITSTATUS (status);
- pid = gva_process_get_pid (process);
- g_debug ("Process %d exited with status %d", pid, status);
- }
+ if (WIFEXITED (status))
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_MAME,
+ "Process %d exited with status %d",
+ gva_process_get_pid (process),
+ WEXITSTATUS (status));
}
static void
@@ -201,10 +199,10 @@ gva_mame_process_spawn (const gchar *arguments,
command_line, &child_pid, &standard_input,
&standard_output, &standard_error, error);
- if (gva_get_debug_flags () & GVA_DEBUG_MAME)
- g_debug (
- "Spawned \"%s\" as process %d",
- command_line, (gint) child_pid);
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_MAME,
+ "Spawned \"%s\" as process %d",
+ command_line, (gint) child_pid);
g_free (command_line);
diff --git a/src/gva-music-button.c b/src/gva-music-button.c
new file mode 100644
index 0000000..f4671e1
--- /dev/null
+++ b/src/gva-music-button.c
@@ -0,0 +1,646 @@
+/* Copyright 2007-2010 Matthew Barnes
+ *
+ * This file is part of GNOME Video Arcade.
+ *
+ * GNOME Video Arcade is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * GNOME Video Arcade is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gva-music-button.h"
+
+#include "gva-history.h"
+#include "gva-util.h"
+
+#define MUSIC_URI "http://www.arcade-history.com/mp3/"
+
+#define GVA_MUSIC_BUTTON_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), GVA_TYPE_MUSIC_BUTTON, GvaMusicButtonPrivate))
+
+struct _GvaMusicButtonPrivate
+{
+#ifdef HAVE_GSTREAMER
+ GstElement *element;
+#endif
+
+ const gchar *game;
+
+ gchar *status;
+ guint status_idle_id;
+
+ guint seeking : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_GAME,
+ PROP_STATUS
+};
+
+enum {
+ PAUSE,
+ PLAY,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static gulong signals[LAST_SIGNAL];
+
+#ifdef HAVE_GSTREAMER
+
+static gboolean
+music_button_notify_status_cb (GvaMusicButton *music_button)
+{
+ music_button->priv->status_idle_id = 0;
+ g_object_notify (G_OBJECT (music_button), "status");
+
+ return FALSE;
+}
+
+static void
+music_button_set_status (GvaMusicButton *music_button,
+ const gchar *status)
+{
+ g_free (music_button->priv->status);
+ music_button->priv->status = g_strdup (status);
+
+ /* Rate-limit status notifications. */
+ if (music_button->priv->status_idle_id == 0)
+ music_button->priv->status_idle_id = g_idle_add (
+ (GSourceFunc) music_button_notify_status_cb,
+ music_button);
+}
+
+static void
+music_button_handle_eos (GvaMusicButton *music_button,
+ GstMessage *message)
+{
+ GstElement *element;
+ GstSeekFlags flags;
+ GstFormat format;
+
+ element = music_button->priv->element;
+
+ /* Repeat music clip. */
+ format = GST_FORMAT_TIME;
+ flags = GST_SEEK_FLAG_FLUSH;
+ gst_element_seek_simple (element, format, flags, 0);
+
+ music_button->priv->seeking = TRUE;
+}
+
+static void
+music_button_handle_error (GvaMusicButton *music_button,
+ GstMessage *message)
+{
+ GstElement *element;
+ const gchar *status = NULL;
+ GError *error = NULL;
+
+ element = music_button->priv->element;
+ gst_element_set_state (element, GST_STATE_NULL);
+
+ gst_message_parse_error (message, &error, NULL);
+
+ if (error->domain == GST_RESOURCE_ERROR)
+ status = _("No music available");
+
+ if (status == NULL)
+ status = _("Unable to play music");
+
+ music_button_set_status (music_button, status);
+ gtk_widget_set_sensitive (GTK_WIDGET (music_button), FALSE);
+
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_GST,
+ "%s (code %d):",
+ g_quark_to_string (error->domain),
+ error->code);
+
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_GST,
+ "%s", error->message);
+
+ g_error_free (error);
+}
+
+static void
+music_button_handle_buffering (GvaMusicButton *music_button,
+ GstMessage *message)
+{
+ gchar *status;
+ gint percent;
+
+ gst_message_parse_buffering (message, &percent);
+
+ status = g_strdup_printf (_("Buffering %d%%..."), percent);
+ music_button_set_status (music_button, status);
+ g_free (status);
+}
+
+static void
+music_button_handle_state_changed (GvaMusicButton *music_button,
+ GstMessage *message)
+{
+ GstElement *element;
+ GtkWidget *image;
+ GtkIconSize icon_size;
+ GstState old_state;
+ GstState new_state;
+ GstState pending;
+ gchar *stock_id;
+
+ element = music_button->priv->element;
+
+ image = gtk_button_get_image (GTK_BUTTON (music_button));
+ gtk_image_get_stock (GTK_IMAGE (image), &stock_id, &icon_size);
+
+ gst_message_parse_state_changed (
+ message, &old_state, &new_state, &pending);
+
+ switch (new_state)
+ {
+ case GST_STATE_NULL:
+ stock_id = GTK_STOCK_MEDIA_PLAY;
+ break;
+
+ case GST_STATE_READY:
+ stock_id = GTK_STOCK_MEDIA_PLAY;
+ break;
+
+ case GST_STATE_PAUSED:
+ if (music_button->priv->seeking)
+ stock_id = GTK_STOCK_MEDIA_PAUSE;
+ else
+ stock_id = GTK_STOCK_MEDIA_PLAY;
+ break;
+
+ case GST_STATE_PLAYING:
+ stock_id = GTK_STOCK_MEDIA_PAUSE;
+ music_button->priv->seeking = FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+ music_button_set_status (music_button, NULL);
+ gtk_image_set_from_stock (GTK_IMAGE (image), stock_id, icon_size);
+
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_GST,
+ "%s -> %s -> %s",
+ gst_element_state_get_name (old_state),
+ gst_element_state_get_name (new_state),
+ gst_element_state_get_name (pending));
+}
+
+static gboolean
+music_button_bus_cb (GstBus *bus,
+ GstMessage *message,
+ GvaMusicButton *music_button)
+{
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_GST,
+ "%s", GST_MESSAGE_TYPE_NAME (message));
+
+ switch (GST_MESSAGE_TYPE (message))
+ {
+ case GST_MESSAGE_EOS:
+ music_button_handle_eos (
+ music_button, message);
+ break;
+
+ case GST_MESSAGE_ERROR:
+ music_button_handle_error (
+ music_button, message);
+ break;
+
+ case GST_MESSAGE_BUFFERING:
+ music_button_handle_buffering (
+ music_button, message);
+ break;
+
+ case GST_MESSAGE_STATE_CHANGED:
+ music_button_handle_state_changed (
+ music_button, message);
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+music_button_setup_element (GvaMusicButton *music_button)
+{
+ GstElement *element;
+ const gchar *game;
+ gchar *uri;
+ guint id;
+
+ element = music_button->priv->element;
+
+ game = gva_music_button_get_game (music_button);
+ id = (game != NULL) ? gva_history_lookup_id (game) : 0;
+
+ gst_element_set_state (element, GST_STATE_NULL);
+
+ uri = (id > 0) ? g_strdup_printf (MUSIC_URI "%u.mp3", id) : NULL;
+ g_object_set (element, "uri", uri, NULL);
+ g_free (uri);
+
+ music_button_set_status (music_button, _("Connecting..."));
+ gtk_widget_set_sensitive (GTK_WIDGET (music_button), TRUE);
+
+ gst_element_set_state (element, GST_STATE_PAUSED);
+}
+
+#endif /* HAVE_GSTREAMER */
+
+static void
+music_button_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ case PROP_GAME:
+ gva_music_button_set_game (
+ GVA_MUSIC_BUTTON (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+music_button_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ case PROP_GAME:
+ g_value_set_string (
+ value, gva_music_button_get_game (
+ GVA_MUSIC_BUTTON (object)));
+ return;
+
+ case PROP_STATUS:
+ g_value_set_string (
+ value, gva_music_button_get_status (
+ GVA_MUSIC_BUTTON (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+music_button_dispose (GObject *object)
+{
+ GvaMusicButtonPrivate *priv;
+
+ priv = GVA_MUSIC_BUTTON_GET_PRIVATE (object);
+
+#ifdef HAVE_GSTREAMER
+ if (priv->element != NULL)
+ {
+ gst_element_set_state (priv->element, GST_STATE_NULL);
+ g_object_unref (priv->element);
+ priv->element = NULL;
+ }
+#endif
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+music_button_finalize (GObject *object)
+{
+ GvaMusicButtonPrivate *priv;
+
+ priv = GVA_MUSIC_BUTTON_GET_PRIVATE (object);
+
+ if (priv->status_idle_id > 0)
+ g_source_remove (priv->status_idle_id);
+
+ g_free (priv->status);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+music_button_constructed (GObject *object)
+{
+ gtk_button_set_image (
+ GTK_BUTTON (object),
+ gtk_image_new_from_stock (
+ GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
+}
+
+static void
+music_button_clicked (GtkButton *button)
+{
+#ifdef HAVE_GSTREAMER
+ GvaMusicButton *music_button;
+ GstElement *element;
+ GstState state;
+
+ music_button = GVA_MUSIC_BUTTON (button);
+ element = music_button->priv->element;
+
+ gst_element_get_state (element, &state, NULL, 0);
+
+ switch (state)
+ {
+ case GST_STATE_NULL:
+ case GST_STATE_READY:
+ case GST_STATE_PAUSED:
+ gva_music_button_play (music_button);
+ break;
+
+ case GST_STATE_PLAYING:
+ gva_music_button_pause (music_button);
+ break;
+
+ default:
+ break;
+ }
+#endif
+}
+
+static void
+music_button_pause (GvaMusicButton *music_button)
+{
+#ifdef HAVE_GSTREAMER
+ GstElement *element;
+
+ element = music_button->priv->element;
+
+ gst_element_set_state (element, GST_STATE_PAUSED);
+#endif
+}
+
+static void
+music_button_play (GvaMusicButton *music_button)
+{
+#ifdef HAVE_GSTREAMER
+ GstElement *element;
+
+ element = music_button->priv->element;
+
+ gst_element_set_state (element, GST_STATE_PLAYING);
+#endif
+}
+
+static void
+music_button_class_init (GvaMusicButtonClass *class)
+{
+ GObjectClass *object_class;
+ GtkButtonClass *button_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (GvaMusicButtonPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = music_button_set_property;
+ object_class->get_property = music_button_get_property;
+ object_class->dispose = music_button_dispose;
+ object_class->finalize = music_button_finalize;
+ object_class->constructed = music_button_constructed;
+
+ button_class = GTK_BUTTON_CLASS (class);
+ button_class->clicked = music_button_clicked;
+
+ class->pause = music_button_pause;
+ class->play = music_button_play;
+
+ /**
+ * GvaMusicButton:game
+ *
+ * The game for which to play a music clip.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_GAME,
+ g_param_spec_string (
+ "game",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * GvaMusicButton:status
+ *
+ * Status message about the music clip.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_STATUS,
+ g_param_spec_string (
+ "status",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE));
+
+ /**
+ * GvaMusicButton::pause
+ * @music_button: the #GvaMusicButton that received the signal
+ *
+ * The ::pause signal is emitted when the user pauses a music clip.
+ **/
+ signals[PAUSE] = g_signal_new (
+ "pause",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvaMusicButtonClass, pause),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * GvaMusicButton::play
+ * @music_button: the #GvaMusicButton
+ *
+ * The ::play signal is emitted when the user plays a music clip.
+ **/
+ signals[PLAY] = g_signal_new (
+ "play",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvaMusicButtonClass, play),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+music_button_init (GvaMusicButton *music_button)
+{
+#ifdef HAVE_GSTREAMER
+ GstElement *element;
+#endif
+
+ music_button->priv = GVA_MUSIC_BUTTON_GET_PRIVATE (music_button);
+
+#ifdef HAVE_GSTREAMER
+ element = gst_element_factory_make ("playbin", "gva-music-player");
+ music_button->priv->element = element;
+
+ gst_bus_add_watch (
+ gst_element_get_bus (element),
+ (GstBusFunc) music_button_bus_cb, music_button);
+#endif
+}
+
+GType
+gva_music_button_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0))
+ {
+ const GTypeInfo type_info =
+ {
+ sizeof (GvaMusicButtonClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) music_button_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GvaMusicButton),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) music_button_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_BUTTON, "GvaMusicButton", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * gva_music_button_new:
+ *
+ * Creates a new #GvaMusicButton.
+ *
+ * Returns: a new #GvaMusicButton
+ **/
+GtkWidget *
+gva_music_button_new (void)
+{
+ return g_object_new (GVA_TYPE_MUSIC_BUTTON, NULL);
+}
+
+/**
+ * gva_music_button_play:
+ * @music_button: a #GvaMusicButton
+ *
+ * Plays a music clip from the game specified by the GvaMusicButton:game
+ * property. The clip will repeat indefinitely until paused or a different
+ * game is chosen.
+ **/
+void
+gva_music_button_play (GvaMusicButton *music_button)
+{
+ g_return_if_fail (GVA_IS_MUSIC_BUTTON (music_button));
+
+ g_signal_emit (music_button, signals[PLAY], 0);
+}
+
+/**
+ * gva_music_button_pause:
+ * @music_button: a #GvaMusicButton
+ *
+ * Pauses a music clip from the game specified by the GvaMusicButton:game
+ * property.
+ **/
+void
+gva_music_button_pause (GvaMusicButton *music_button)
+{
+ g_return_if_fail (GVA_IS_MUSIC_BUTTON (music_button));
+
+ g_signal_emit (music_button, signals[PAUSE], 0);
+}
+
+/**
+ * gva_music_button_get_game:
+ * @music_button: a #GvaMusicButton
+ *
+ * Returns the name of the game for which to play a music clip.
+ *
+ * Returns: the game for which to play a music clip
+ **/
+const gchar *
+gva_music_button_get_game (GvaMusicButton *music_button)
+{
+ g_return_val_if_fail (GVA_IS_MUSIC_BUTTON (music_button), NULL);
+
+ return music_button->priv->game;
+}
+
+/**
+ * gva_music_button_set_game:
+ * @music_button: a #GvaMusicButton
+ * @game: the name of a game
+ *
+ * Sets the name of the game for which to play a music clip. Use
+ * gva_music_button_play() to play the clip.
+ **/
+void
+gva_music_button_set_game (GvaMusicButton *music_button,
+ const gchar *game)
+{
+ g_return_if_fail (GVA_IS_MUSIC_BUTTON (music_button));
+
+ if (game != NULL)
+ game = g_intern_string (game);
+
+ music_button->priv->game = game;
+
+#ifdef HAVE_GSTREAMER
+ music_button_setup_element (music_button);
+#endif
+
+ g_object_notify (G_OBJECT (music_button), "game");
+}
+
+/**
+ * gva_music_button_get_status:
+ * @music_button: a #GvaMusicButton
+ *
+ * Returns a status message about the music clip, such as buffering
+ * progress or whether a music clip is available for the selected game.
+ *
+ * Returns: a status message about the music clip
+ **/
+const gchar *
+gva_music_button_get_status (GvaMusicButton *music_button)
+{
+ g_return_val_if_fail (GVA_IS_MUSIC_BUTTON (music_button), NULL);
+
+ return music_button->priv->status;
+}
diff --git a/src/gva-music-button.h b/src/gva-music-button.h
new file mode 100644
index 0000000..e887fc1
--- /dev/null
+++ b/src/gva-music-button.h
@@ -0,0 +1,91 @@
+/* Copyright 2007-2010 Matthew Barnes
+ *
+ * This file is part of GNOME Video Arcade.
+ *
+ * GNOME Video Arcade is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * GNOME Video Arcade is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: gva-music-button
+ * @short_description: Button for streaming music
+ *
+ * A #GvaMusicButton toggles between playing and pausing in-game music
+ * clips streamed from http://www.arcade-history.com/.
+ *
+ * This requires arcade history information from a 'history.dat' file.
+ **/
+
+#ifndef GVA_MUSIC_BUTTON_H
+#define GVA_MUSIC_BUTTON_H
+
+#include "gva-common.h"
+
+/* Standard GObject macros */
+#define GVA_TYPE_MUSIC_BUTTON \
+ (gva_music_button_get_type ())
+#define GVA_MUSIC_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), GVA_TYPE_MUSIC_BUTTON, GvaMusicButton))
+#define GVA_MUSIC_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), GVA_TYPE_MUSIC_BUTTON, GvaMusicButtonClass))
+#define GVA_IS_MUSIC_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), GVA_TYPE_MUSIC_BUTTON))
+#define GVA_IS_MUSIC_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), GVA_TYPE_MUSIC_BUTTON))
+#define GVA_MUSIC_BUTTON_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), GVA_TYPE_MUSIC_BUTTON, GvaMusicButtonClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GvaMusicButton GvaMusicButton;
+typedef struct _GvaMusicButtonClass GvaMusicButtonClass;
+typedef struct _GvaMusicButtonPrivate GvaMusicButtonPrivate;
+
+/**
+ * GvaMusicButton:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _GvaMusicButton
+{
+ GtkButton parent;
+ GvaMusicButtonPrivate *priv;
+};
+
+struct _GvaMusicButtonClass
+{
+ GtkButtonClass parent_class;
+
+ /* Signals */
+ void (*play) (GvaMusicButton *music_button);
+ void (*pause) (GvaMusicButton *music_button);
+};
+
+GType gva_music_button_get_type (void);
+GtkWidget * gva_music_button_new (void);
+void gva_music_button_play (GvaMusicButton *music_button);
+void gva_music_button_pause (GvaMusicButton *music_button);
+const gchar * gva_music_button_get_game (GvaMusicButton *music_button);
+void gva_music_button_set_game (GvaMusicButton *music_button,
+ const gchar *game);
+const gchar * gva_music_button_get_status (GvaMusicButton *music_button);
+
+G_END_DECLS
+
+#endif /* GVA_MUSIC_BUTTON_H */
diff --git a/src/gva-preferences.c b/src/gva-preferences.c
index a39bc80..c3c4408 100644
--- a/src/gva-preferences.c
+++ b/src/gva-preferences.c
@@ -33,6 +33,19 @@
void
gva_preferences_init (void)
{
+ /* Auto Play */
+
+ /* This actually appears in the Properties window,
+ * but it's still a preference so we manage it here. */
+
+ gtk_action_connect_proxy (
+ GVA_ACTION_AUTO_PLAY,
+ GVA_WIDGET_PROPERTIES_MUSIC_AUTO_PLAY);
+
+ gconf_bridge_bind_property (
+ gconf_bridge_get (), GVA_GCONF_AUTO_PLAY_KEY,
+ G_OBJECT (GVA_ACTION_AUTO_PLAY), "active");
+
/* Auto Save */
gtk_action_connect_proxy (
@@ -74,6 +87,48 @@ gva_preferences_init (void)
}
/**
+ * gva_preferences_get_auto_play:
+ *
+ * Returns the user's preference for whether to automatically
+ * play a music clip of the selected game when the user opens
+ * the Properties window or when the user selects a different
+ * game while the Properties window is visible.
+ *
+ * Returns: %TRUE to automatically play music clips
+ **/
+gboolean
+gva_preferences_get_auto_play (void)
+{
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_AUTO_PLAY);
+
+ return gtk_toggle_action_get_active (toggle_action);
+}
+
+/**
+ * gva_preferences_set_auto_play:
+ * @auto_play: the user's preference
+ *
+ * Accepts the user's preference for whether to automatically
+ * play a music clip of the selected game when the user opens
+ * the Properties window or when the user selects a different
+ * game while the Properties window is visible.
+ *
+ * The preference is stored in GConf key
+ * <filename>/apps/gnome-video-arcade/auto-play</filename>.
+ **/
+void
+gva_preferences_set_auto_play (gboolean auto_play)
+{
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_AUTO_PLAY);
+
+ gtk_toggle_action_set_active (toggle_action, auto_play);
+}
+
+/**
* gva_preferences_get_auto_save:
*
* Returns the user's preference for whether to restore the emulated
@@ -84,8 +139,11 @@ gva_preferences_init (void)
gboolean
gva_preferences_get_auto_save (void)
{
- return gtk_toggle_action_get_active (
- GTK_TOGGLE_ACTION (GVA_ACTION_AUTO_SAVE));
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_AUTO_SAVE);
+
+ return gtk_toggle_action_get_active (toggle_action);
}
/**
@@ -101,8 +159,11 @@ gva_preferences_get_auto_save (void)
void
gva_preferences_set_auto_save (gboolean auto_save)
{
- gtk_toggle_action_set_active (
- GTK_TOGGLE_ACTION (GVA_ACTION_AUTO_SAVE), auto_save);
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_AUTO_SAVE);
+
+ gtk_toggle_action_set_active (toggle_action, auto_save);
}
/**
@@ -116,8 +177,11 @@ gva_preferences_set_auto_save (gboolean auto_save)
gboolean
gva_preferences_get_full_screen (void)
{
- return gtk_toggle_action_get_active (
- GTK_TOGGLE_ACTION (GVA_ACTION_FULL_SCREEN));
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_FULL_SCREEN);
+
+ return gtk_toggle_action_get_active (toggle_action);
}
/**
@@ -133,8 +197,11 @@ gva_preferences_get_full_screen (void)
void
gva_preferences_set_full_screen (gboolean full_screen)
{
- gtk_toggle_action_set_active (
- GTK_TOGGLE_ACTION (GVA_ACTION_FULL_SCREEN), full_screen);
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_FULL_SCREEN);
+
+ gtk_toggle_action_set_active (toggle_action, full_screen);
}
/**
@@ -148,8 +215,11 @@ gva_preferences_set_full_screen (gboolean full_screen)
gboolean
gva_preferences_get_show_clones (void)
{
- return gtk_toggle_action_get_active (
- GTK_TOGGLE_ACTION (GVA_ACTION_SHOW_CLONES));
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_SHOW_CLONES);
+
+ return gtk_toggle_action_get_active (toggle_action);
}
/**
@@ -165,8 +235,11 @@ gva_preferences_get_show_clones (void)
void
gva_preferences_set_show_clones (gboolean show_clones)
{
- gtk_toggle_action_set_active (
- GTK_TOGGLE_ACTION (GVA_ACTION_SHOW_CLONES), show_clones);
+ GtkToggleAction *toggle_action;
+
+ toggle_action = GTK_TOGGLE_ACTION (GVA_ACTION_SHOW_CLONES);
+
+ gtk_toggle_action_set_active (toggle_action, show_clones);
}
/**
diff --git a/src/gva-preferences.h b/src/gva-preferences.h
index 2816327..b29edcb 100644
--- a/src/gva-preferences.h
+++ b/src/gva-preferences.h
@@ -31,6 +31,8 @@
G_BEGIN_DECLS
void gva_preferences_init (void);
+gboolean gva_preferences_get_auto_play (void);
+void gva_preferences_set_auto_play (gboolean auto_play);
gboolean gva_preferences_get_auto_save (void);
void gva_preferences_set_auto_save (gboolean auto_save);
gboolean gva_preferences_get_full_screen (void);
diff --git a/src/gva-process.c b/src/gva-process.c
index f0e6c80..12aa042 100644
--- a/src/gva-process.c
+++ b/src/gva-process.c
@@ -258,7 +258,9 @@ process_debug_message (GvaProcess *process,
pid = gva_process_get_pid (process);
copy = g_strchomp (g_strdup (line));
- g_debug ("Process %d %s %s", (gint) pid, sep, copy);
+ g_log (
+ G_LOG_DOMAIN, GVA_DEBUG_IO,
+ "Process %d %s %s", (gint) pid, sep, copy);
g_free (copy);
}
@@ -449,7 +451,7 @@ process_class_init (GvaProcessClass *class)
class->stderr_read_line = process_stderr_read_line;
/**
- * GvaProcess:pid:
+ * GvaProcess:pid
*
* The ID of the child process.
**/
@@ -465,7 +467,7 @@ process_class_init (GvaProcessClass *class)
G_PARAM_CONSTRUCT_ONLY));
/**
- * GvaProcess:stdin:
+ * GvaProcess:stdin
*
* The file descriptor for the child process' stdin pipe.
**/
@@ -481,7 +483,7 @@ process_class_init (GvaProcessClass *class)
G_PARAM_CONSTRUCT_ONLY));
/**
- * GvaProcess:stdout:
+ * GvaProcess:stdout
*
* The file descriptor for the child process' stdout pipe.
**/
@@ -497,7 +499,7 @@ process_class_init (GvaProcessClass *class)
G_PARAM_CONSTRUCT_ONLY));
/**
- * GvaProcess:stderr:
+ * GvaProcess:stderr
*
* The file descriptor for the child process' stderr pipe.
**/
@@ -513,7 +515,7 @@ process_class_init (GvaProcessClass *class)
G_PARAM_CONSTRUCT_ONLY));
/**
- * GvaProcess:priority:
+ * GvaProcess:priority
*
* Priority of the event sources that watch for incoming data.
**/
@@ -530,7 +532,7 @@ process_class_init (GvaProcessClass *class)
G_PARAM_CONSTRUCT_ONLY));
/**
- * GvaProcess:progress:
+ * GvaProcess:progress
*
* Progress value, the meaning of which is defined by the
* application.
@@ -747,8 +749,7 @@ gva_process_write_stdin (GvaProcess *process,
g_return_val_if_fail (GVA_IS_PROCESS (process), FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- if (gva_get_debug_flags () & GVA_DEBUG_IO)
- process_debug_message (process, data, "<<<");
+ process_debug_message (process, data, "<<<");
while (status == G_IO_STATUS_AGAIN)
status = g_io_channel_write_chars (
@@ -828,8 +829,7 @@ gva_process_stdout_read_line (GvaProcess *process)
g_return_val_if_fail (class->stdout_read_line != NULL, NULL);
line = class->stdout_read_line (process);
- if (gva_get_debug_flags () & GVA_DEBUG_IO)
- process_debug_message (process, line, ">>>");
+ process_debug_message (process, line, ">>>");
return line;
}
@@ -858,8 +858,7 @@ gva_process_stderr_read_line (GvaProcess *process)
g_return_val_if_fail (class->stderr_read_line != NULL, NULL);
line = class->stderr_read_line (process);
- if (gva_get_debug_flags () & GVA_DEBUG_IO)
- process_debug_message (process, line, "!!!");
+ process_debug_message (process, line, "!!!");
return line;
}
diff --git a/src/gva-properties.c b/src/gva-properties.c
index 05db8c9..667b340 100644
--- a/src/gva-properties.c
+++ b/src/gva-properties.c
@@ -26,6 +26,8 @@
#include "gva-game-store.h"
#include "gva-history.h"
#include "gva-link-button.h"
+#include "gva-music-button.h"
+#include "gva-preferences.h"
#include "gva-tree-view.h"
#include "gva-ui.h"
#include "gva-util.h"
@@ -473,6 +475,19 @@ properties_update_history (GtkTreeModel *model,
}
static void
+properties_update_music (const gchar *name)
+{
+ GvaMusicButton *music_button;
+
+ music_button = GVA_MUSIC_BUTTON (GVA_WIDGET_PROPERTIES_MUSIC_BUTTON);
+ gva_music_button_set_game (music_button, name);
+
+ if (GTK_WIDGET_VISIBLE (GVA_WIDGET_PROPERTIES_WINDOW)
+ && gva_preferences_get_auto_play ())
+ gva_music_button_play (music_button);
+}
+
+static void
properties_update_sound (const gchar *name)
{
GtkWidget *label;
@@ -722,6 +737,25 @@ properties_selection_changed_cb (GtkTreeSelection *selection)
properties_update_timeout_cb, NULL);
}
+static void
+properties_notify_music_status_cb (GvaMusicButton *music_button)
+{
+ GtkWidget *label;
+ const gchar *status;
+ gchar *markup;
+
+ label = GVA_WIDGET_PROPERTIES_MUSIC_STATUS;
+ status = gva_music_button_get_status (music_button);
+
+ /* Use whitespace to keep the widget height stable. */
+ if (status == NULL)
+ status = " ";
+
+ markup = g_markup_printf_escaped ("<small>%s</small>", status);
+ gtk_label_set_markup (GTK_LABEL (label), markup);
+ g_free (markup);
+}
+
/**
* gva_properties_init:
*
@@ -764,6 +798,10 @@ gva_properties_init (void)
gtk_tree_view_get_selection (view), "changed",
G_CALLBACK (properties_selection_changed_cb), NULL);
+ g_signal_connect (
+ GVA_WIDGET_PROPERTIES_MUSIC_BUTTON, "notify::status",
+ G_CALLBACK (properties_notify_music_status_cb), NULL);
+
font_name = gva_get_monospace_font_name ();
desc = pango_font_description_from_string (font_name);
gtk_widget_modify_font (text_view, desc);
@@ -778,6 +816,10 @@ gva_properties_init (void)
widget = GVA_WIDGET_PROPERTIES_STATUS_FRAME;
gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, color);
+#ifndef HAVE_GSTREAMER
+ gtk_widget_hide (GVA_WIDGET_PROPERTIES_MUSIC_TABLE);
+#endif
+
#ifndef HISTORY_FILE
/* Hide the history page if we have no history file. */
notebook = GTK_NOTEBOOK (GVA_WIDGET_PROPERTIES_NOTEBOOK);
@@ -829,6 +871,7 @@ gva_properties_show_game (const gchar *game)
properties_update_cpu (game);
properties_update_header (model, &iter);
properties_update_history (model, &iter);
+ properties_update_music (game);
properties_update_sound (game);
properties_update_status (model, &iter);
properties_update_video (game);
@@ -838,19 +881,21 @@ gva_properties_show_game (const gchar *game)
}
/**
- * gva_properties_close_clicked_cb:
+ * gva_properties_hide_cb:
* @window: the "Properties" window
* @button: the "Close" button
*
- * Handler for #GtkButton::clicked signals to the "Close" button.
+ * Handler for #GtkWidget::show signals to the "Properties" window.
*
- * Hides @window.
+ * Stops in-game music clip.
**/
void
-gva_properties_close_clicked_cb (GtkWindow *window,
- GtkButton *button)
+gva_properties_hide_cb (GtkWindow *window)
{
- gtk_widget_hide (GTK_WIDGET (window));
+ GvaMusicButton *music_button;
+
+ music_button = GVA_MUSIC_BUTTON (GVA_WIDGET_PROPERTIES_MUSIC_BUTTON);
+ gva_music_button_pause (music_button);
}
/**
@@ -859,10 +904,18 @@ gva_properties_close_clicked_cb (GtkWindow *window,
*
* Handler for #GtkWidget::show signals to the "Properties" window.
*
- * Resets all scrolled windows to the top.
+ * Resets all scrolled windows to the top, and starts in-game music clip
+ * if the "auto-play" preference is enabled.
**/
void
gva_properties_show_cb (GtkWindow *window)
{
+ GvaMusicButton *music_button;
+
+ music_button = GVA_MUSIC_BUTTON (GVA_WIDGET_PROPERTIES_MUSIC_BUTTON);
+
+ if (gva_preferences_get_auto_play ())
+ gva_music_button_play (music_button);
+
properties_scroll_to_top ();
}
diff --git a/src/gva-properties.h b/src/gva-properties.h
index f9161e2..48db872 100644
--- a/src/gva-properties.h
+++ b/src/gva-properties.h
@@ -35,8 +35,7 @@ void gva_properties_show_game (const gchar *game);
/* Signal Handlers */
-void gva_properties_close_clicked_cb (GtkWindow *window,
- GtkButton *button);
+void gva_properties_hide_cb (GtkWindow *window);
void gva_properties_show_cb (GtkWindow *window);
G_END_DECLS
diff --git a/src/gva-ui.c b/src/gva-ui.c
index 74adf6f..0d79d6f 100644
--- a/src/gva-ui.c
+++ b/src/gva-ui.c
@@ -26,6 +26,7 @@
#include "gva-game-store.h"
#include "gva-main.h"
#include "gva-mame.h"
+#include "gva-music-button.h"
#include "gva-mute-button.h"
#include "gva-play-back.h"
#include "gva-preferences.h"
@@ -171,6 +172,14 @@ action_add_column_cb (GtkAction *action,
}
/**
+ * GVA_ACTION_AUTO_PLAY:
+ *
+ * This toggle action tracks the user's preference for whether to
+ * automatically start playing a music clip from the selected game
+ * (if available) when the Properties window is open.
+ **/
+
+/**
* GVA_ACTION_AUTO_SAVE:
*
* This toggle action tracks the user's preference for whether to
@@ -281,6 +290,7 @@ action_next_game_cb (GtkAction *action)
static void
action_play_back_cb (GtkAction *action)
{
+ GtkWidget *widget;
GvaProcess *process;
GtkTreeModel *model;
GtkTreeView *view;
@@ -309,6 +319,9 @@ action_play_back_cb (GtkAction *action)
inpname = g_strdelimit (g_path_get_basename (inpfile), ".", '\0');
g_free (inpfile);
+ widget = GVA_WIDGET_PROPERTIES_MUSIC_BUTTON;
+ gva_music_button_pause (GVA_MUSIC_BUTTON (widget));
+
process = gva_mame_playback_game (name, inpname, &error);
gva_error_handle (&error);
@@ -429,6 +442,7 @@ action_quit_cb (GtkAction *action)
static void
action_record_cb (GtkAction *action)
{
+ GtkWidget *widget;
GvaProcess *process;
const gchar *name;
gchar *inpname;
@@ -439,6 +453,9 @@ action_record_cb (GtkAction *action)
inpname = gva_choose_inpname (name);
+ widget = GVA_WIDGET_PROPERTIES_MUSIC_BUTTON;
+ gva_music_button_pause (GVA_MUSIC_BUTTON (widget));
+
process = gva_mame_record_game (name, inpname, &error);
gva_error_handle (&error);
@@ -604,6 +621,7 @@ action_show_play_back_cb (GtkAction *action)
static void
action_start_cb (GtkAction *action)
{
+ GtkWidget *widget;
GvaProcess *process;
const gchar *name;
GError *error = NULL;
@@ -614,6 +632,9 @@ action_start_cb (GtkAction *action)
if (!gva_preferences_get_auto_save ())
gva_mame_delete_save_state (name);
+ widget = GVA_WIDGET_PROPERTIES_MUSIC_BUTTON;
+ gva_music_button_pause (GVA_MUSIC_BUTTON (widget));
+
process = gva_mame_run_game (name, &error);
gva_error_handle (&error);
@@ -828,6 +849,14 @@ static GtkActionEntry entries[] =
static GtkToggleActionEntry toggle_entries[] =
{
+ { "auto-play",
+ NULL,
+ N_("Play music _automatically"),
+ NULL,
+ N_("Automatically play a music clip from the selected game"),
+ NULL, /* GConfBridge monitors the state */
+ FALSE }, /* GConf overrides this */
+
{ "auto-save",
NULL,
N_("_Restore previous state when starting a game"),
diff --git a/src/gva-ui.h b/src/gva-ui.h
index 986cc26..2789be3 100644
--- a/src/gva-ui.h
+++ b/src/gva-ui.h
@@ -31,6 +31,7 @@
/* Actions */
#define GVA_ACTION_ABOUT (gva_ui_get_action ("about"))
+#define GVA_ACTION_AUTO_PLAY (gva_ui_get_action ("auto-play"))
#define GVA_ACTION_AUTO_SAVE (gva_ui_get_action ("auto-save"))
#define GVA_ACTION_CONTENTS (gva_ui_get_action ("contents"))
#define GVA_ACTION_FULL_SCREEN (gva_ui_get_action ("full-screen"))
@@ -142,6 +143,14 @@
(gva_ui_get_widget ("properties-imperfect-graphic-label"))
#define GVA_WIDGET_PROPERTIES_IMPERFECT_SOUND_LABEL \
(gva_ui_get_widget ("properties-imperfect-sound-label"))
+#define GVA_WIDGET_PROPERTIES_MUSIC_AUTO_PLAY \
+ (gva_ui_get_widget ("properties-music-auto-play"))
+#define GVA_WIDGET_PROPERTIES_MUSIC_BUTTON \
+ (gva_ui_get_widget ("properties-music-button"))
+#define GVA_WIDGET_PROPERTIES_MUSIC_STATUS \
+ (gva_ui_get_widget ("properties-music-status"))
+#define GVA_WIDGET_PROPERTIES_MUSIC_TABLE \
+ (gva_ui_get_widget ("properties-music-table"))
#define GVA_WIDGET_PROPERTIES_NOTEBOOK \
(gva_ui_get_widget ("properties-notebook"))
#define GVA_WIDGET_PROPERTIES_ORIGINAL_LINKS \
diff --git a/src/gva-util.c b/src/gva-util.c
index 08ec21c..b6afb24 100644
--- a/src/gva-util.c
+++ b/src/gva-util.c
@@ -38,6 +38,18 @@ gchar *opt_inspect;
gboolean opt_version;
gboolean opt_which_emulator;
+static void
+log_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ const gchar *log_level_id)
+{
+ if ((gva_get_debug_flags () & log_level) != 0)
+ g_print (
+ "%s-LOG-DEBUG-%s: %s\n",
+ log_domain, log_level_id, message);
+}
+
static gboolean
inpname_exists (const gchar *inppath, const gchar *inpname)
{
@@ -166,11 +178,28 @@ gva_get_debug_flags (void)
{ "mame", GVA_DEBUG_MAME },
{ "sql", GVA_DEBUG_SQL },
{ "io", GVA_DEBUG_IO },
- { "inp", GVA_DEBUG_INP }
+ { "inp", GVA_DEBUG_INP },
+ { "gst", GVA_DEBUG_GST }
};
const gchar *env = g_getenv ("GVA_DEBUG");
+ g_log_set_handler (
+ G_LOG_DOMAIN, GVA_DEBUG_MAME,
+ (GLogFunc) log_handler, "MAME");
+ g_log_set_handler (
+ G_LOG_DOMAIN, GVA_DEBUG_SQL,
+ (GLogFunc) log_handler, "SQL");
+ g_log_set_handler (
+ G_LOG_DOMAIN, GVA_DEBUG_IO,
+ (GLogFunc) log_handler, "IO");
+ g_log_set_handler (
+ G_LOG_DOMAIN, GVA_DEBUG_INP,
+ (GLogFunc) log_handler, "INP");
+ g_log_set_handler (
+ G_LOG_DOMAIN, GVA_DEBUG_GST,
+ (GLogFunc) log_handler, "GST");
+
flags = g_parse_debug_string (
(env != NULL) ? env : "", debug_keys,
G_N_ELEMENTS (debug_keys));
diff --git a/src/gva-util.h b/src/gva-util.h
index 3045d4b..1de1c6e 100644
--- a/src/gva-util.h
+++ b/src/gva-util.h
@@ -43,6 +43,8 @@ G_BEGIN_DECLS
* Print all communication between GVA and MAME.
* @GVA_DEBUG_INP:
* Print information about input files.
+ * @GVA_DEBUG_GST:
+ * Print GStreamer activity.
*
* These flags indicate which types of debugging messages will be triggered
* at runtime. Debugging messages can be triggered by setting the GVA_DEBUG
@@ -50,11 +52,12 @@ G_BEGIN_DECLS
**/
typedef enum
{
- GVA_DEBUG_NONE = 0,
- GVA_DEBUG_MAME = 1 << 0,
- GVA_DEBUG_SQL = 1 << 1,
- GVA_DEBUG_IO = 1 << 2,
- GVA_DEBUG_INP = 1 << 3
+ GVA_DEBUG_NONE = 0,
+ GVA_DEBUG_MAME = 1 << (G_LOG_LEVEL_USER_SHIFT + 0),
+ GVA_DEBUG_SQL = 1 << (G_LOG_LEVEL_USER_SHIFT + 1),
+ GVA_DEBUG_IO = 1 << (G_LOG_LEVEL_USER_SHIFT + 2),
+ GVA_DEBUG_INP = 1 << (G_LOG_LEVEL_USER_SHIFT + 3),
+ GVA_DEBUG_GST = 1 << (G_LOG_LEVEL_USER_SHIFT + 4)
} GvaDebugFlags;
gchar * gva_choose_inpname (const gchar *game);
diff --git a/src/main.c b/src/main.c
index c1a5f28..f99a014 100644
--- a/src/main.c
+++ b/src/main.c
@@ -233,6 +233,14 @@ main (gint argc, gchar **argv)
g_error ("%s", error->message);
#endif
+#ifdef HAVE_GSTREAMER
+ if (!gst_init_check (&argc, &argv, &error))
+ g_error ("%s", error->message);
+#endif
+
+ /* This installs handlers for our custom debug log levels. */
+ gva_get_debug_flags ();
+
/* Change the working directory to that of the MAME executable.
* Why? Because SDLMAME's default configuration uses relative
* search paths such as "rompath = roms". The paths are relative
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]