r2949 - in trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2: . images src
abraxa at sita.openmoko.org
abraxa at sita.openmoko.org
Tue Sep 11 11:01:13 CEST 2007
Author: abraxa
Date: 2007-09-11 11:00:58 +0200 (Tue, 11 Sep 2007)
New Revision: 2949
Added:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-file-chooser.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-generic.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-mp3.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-ogg.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-unplayable.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlist-editor.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlist-new.png
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlists.png
Removed:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-tracktype-general.png
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/AUTHORS
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/README
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/Makefile.am
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.c
Log:
Added "Add file" UI and necessary backend functions
Forcing alsasink as gstreamer output plugin, hoping that'll bring down the CPU usage from 90% with PulseAudio
Various bugfixes
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/AUTHORS
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/AUTHORS 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/AUTHORS 2007-09-11 09:00:58 UTC (rev 2949)
@@ -1,138 +1,2 @@
-BMP - beep media player (C) GPL 2003-2005
-
-Authors alphabetically
-----------------------
-
-Artem Baguinski <artm at v2.nl>
-Edward Brocklesby <ejb at goth.net>
-Chong Kai Xiong <descender at phreaker.net>
-Milosz Derezynski <m.derezynski at arcor.de>
-David Lau <coder_sku at users.sourceforge.net>
-Ole Andre Vadla Ravnaas <oleavr at jblinux.net>
-Michiel Sikkes <michiel at eyesopened.nl>
-
-ClearSky skin by Will Reinhart <willsan at xepher.net>
-
-
-Patch Authors
--------------
-
-Andrei Badea
-Peter Behroozi
-Bernard Blackham
-Oliver Blin
-David Le Brun
-Tomas Bzatek
-Liviu Danicel
-Jon Dowland
-Artur Frysiak
-Sebastian Kapfer
-Lukas Koberstein
-Dan Korostelev
-Oliver Lehmann
-Jolan Luff
-Mike Lundy
-Michael Marineau
-Tim-Philipp Muller
-Julien Portalier
-Andrew Ruder
-Olivier Samyn
-John Spray
-Takashi Iwai
-Martijn Vernooij
-Thierry Vignaud
-
-
-Translators
------------
-
-Brazilian Portuguese - Philipi Pinto <philipi at gmx.net>
-Breton - Thierry Vignaud <tvignaud at mandrakesoft.com>
-Czech - Jan Narovec <jnarovec at students.zcu.cz>
-Dutch - Laurens Buhler <masterpe at xs4all.nl>
-German - Matthias Debus <psic4t at netbands.de>
-Georgian - George Machitidze <giomac at global-erty.net>
-Greek - Kouzinopoulos Haris <haris at mpa.gr>
- Stavros Giannouris <stavrosg2002 at freemail.gr>
-Finnish - Pauli Virtanen <pauli.virtanen at hut.fi>
-French - David Le Brun <david at dyn-ns.net>
-Hindi - Dhananjaya Sharma <dysxhi at yahoo.co.in>
-Hungarian - Laszlo Dvornik <dvornik at gnome.hu>
-Italian - Alessio D'Ascanio <otaku at fastwebnet.it>
-Japanese - Takeshi Aihana <aihana at gnome.gr.jp>
-Korean - DongCheon Park <dcpark at kaist.ac.kr>
-Lithuanian - Rimas Kudelis <rq at akl.lt>
-Macedonian - Arangel Angov <ufo at linux.net.mk>
-Polish - Jacek Wolszczak <shutdownrunner at o2.pl>
-Romanian - Liviu Danicel <liviu.danicel at spymac.com>
-Russian - Pavlo Bohmat <bohm at ukr.net>
- Dan Korostelev <dan at ats.energo.ru>
- Vitaly Lipatov <lav at altlinux.ru>
-Simplified Chinese - Chong Kai Xiong <descender at phreaker.net>
-Traditional Chinese - Chao-Hsiung Liao <pesder.liao at msa.hinet.net>
-Slovak - Pavel Kanzelsberger <kanzels at zmail.sk>
-Spanish - Francisco Javier F. Serrador <serrador at cvs.gnome.org>
-Swedish - Martin Persenius <martin at persenius.net>
-Ukrainian - Mykola Lynnyk<definer at users.sf.net>
-Welsh - Edward Brocklesby <ejb at goth.net>
- (Based on XMMS from Rhoslyn Prys <rhoslyn.prys at meddal.org.uk>)
-
-
-(please tell us if we left your name out)
-
--
-
-Based on:
-
-XMMS - X Multimedia System (C)1998-2003
-
- Main Programming: Peter Alm
-
- Additional Programming: Håvard Kvålen
- Derrik Pates
-
- With Additional Help: Sean Atkinson
- Jorn Baayen
- James M. Cape
- Anders Carlsson (effect plugins)
- Chun-Chung Chen (xfont patch)
- Tim Ferguson (joystick plugin)
- Ben Gertzfield
- Vesa Halttunen
- Logan Hanks
- Eric L. Hernes (FreeBSD patches)
- Ville Herva
- higway (MMX)
- Michael Hipp and others (MPG123 engine)
- Olle Hällnäs (compiling fixes)
- David Jacoby
- Osamu Kayasono (3DNow!)
- Lyle B Kempler
- J. Nick Koston (MikMod plugin)
- Aaron Lehmann
- Johan Levin (echo + stereo plugin)
- Eric Lindvall
- Colin Marquardt
- Willem Monsuwe
- John Riddoch (Solaris plugin)
- Josip Rodin
- Pablo Saratxaga (i18n)
- Carl van Schaik (pro logic plugin)
- Jörg Schuler
- Charles Sielski (irman plugin)
- Espen Skoglund
- Matthieu Sozeau (ALSA plugin)
- Kimura Takuhiro (3DNow!)
- Zinx Verituse
- Ryan Weaver (RPMs among other things)
- Chris Wilson
- Dave Yearke
- Stephan K. Zitz
-
- Default skin: Leonard "Blayde" Tan
- Robin Sylvestre (Equalizer and Playlist)
- Thomas Nilsson (New titles, and cleanups)
-
- Homepage and Graphics: Thomas Nilsson
-
- Support and Docs: Olle Hällnäs
+Soeren Apel (Abraxa) <abraxa at dar-clan.de>
+Michael 'Mickey' Lauer <mlauer at vanille-media.de>
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/README
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/README 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/README 2007-09-11 09:00:58 UTC (rev 2949)
@@ -0,0 +1,8 @@
+This is the OpenMoko media player for OM2007.2, enabling you to playback audio
+(and eventually video) on your smartphone.
+
+It stores XSPF playlists in ~/playlists and uses the SD card as media storage
+by default. Please be aware that there are issues still - especially when it
+comes to the user interface. They'll be fixed however, so bear with me :)
+
+ -Soeren
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO 2007-09-11 09:00:58 UTC (rev 2949)
@@ -1,9 +1,9 @@
UI:
- Add repeat mode indicator (different button pixmaps)
Make FFWD/REW buttons trigger repeatedly
Make Prev/Next buttons sensitive depending on playlist state
m3u import
+ QVGA support through external style definitions
Backend:
Use GConf
@@ -12,13 +12,9 @@
Check for unicode compliance
Issues:
- How/where to store playlists? -> Single common path, omitting path chooser
Use EQ presets only or allow individual band adjustment?
How to adjust equalizer?
Reduce call frequency of omp_playback_get_track_length()
-Build process:
- Bitbake recipe and its integration into OE
-
Documentation:
- -/-
+ Update wiki
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/Makefile.am
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/Makefile.am 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/Makefile.am 2007-09-11 09:00:58 UTC (rev 2949)
@@ -2,8 +2,6 @@
images_DATA = \
background.png \
- btn-white.png \
- btn-white-p.png \
ico-track.png \
ico-time.png \
ico-repeat-off.png \
@@ -14,7 +12,14 @@
ico-shuffle-off.png \
ico-balance-left.png \
ico-balance-right.png \
- ico-tracktype-general.png \
+ ico-filetype-unplayable.png \
+ ico-filetype-generic.png \
+ ico-filetype-mp3.png \
+ ico-filetype-ogg.png \
+ ico-playlists.png \
+ ico-playlist-new.png \
+ ico-playlist-editor.png \
+ ico-file-chooser.png \
ind-music-eq-00.png \
ind-music-eq-01.png \
ind-music-eq-02.png \
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-file-chooser.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-file-chooser.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-generic.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-generic.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-mp3.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-mp3.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-ogg.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-ogg.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-unplayable.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-filetype-unplayable.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlist-editor.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlist-editor.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlist-new.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlist-new.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlists.png
===================================================================
(Binary files differ)
Property changes on: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-playlists.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Deleted: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/images/ico-tracktype-general.png
===================================================================
(Binary files differ)
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/editor_page.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -33,7 +33,7 @@
#include "playlist.h"
#include "guitools.h"
-/// Enumeration for the track list columns
+/// Enumeration of the track list columns
enum
{
TYPE_COLUMN,
@@ -92,7 +92,7 @@
if (artist)
{
- if (strcmp(artist, "") != 0)
+ if (artist[0] != 0)
{
caption = g_strdup_printf(_("%1$s - %2$s"), artist, title);
} else {
@@ -122,13 +122,23 @@
}
/**
+ * Updates the track list if the track count changed
+ */
+void
+omp_editor_page_update_track_count(gpointer instance, gpointer user_data)
+{
+ omp_editor_page_list_populate();
+}
+
+/**
* Callback for the "add track" button
*/
void
omp_editor_page_add_clicked(gpointer instance, gpointer user_data)
{
// Show file chooser
- omp_show_tab(OMP_TAB_FILE_CHOOSER);
+ omp_tab_show(OMP_TAB_FILE_CHOOSER);
+ omp_tab_focus(OMP_TAB_FILE_CHOOSER);
}
/**
@@ -137,7 +147,7 @@
gboolean
omp_editor_page_list_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
- return TRUE;
+ return FALSE;
}
/**
@@ -171,7 +181,7 @@
if (artist)
{
- if (strcmp(artist, "") != 0)
+ if (artist[0] != 0)
{
caption = g_strdup_printf(_("%1$s - %2$s"), artist, title);
} else {
@@ -307,5 +317,8 @@
g_signal_connect(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_INFO_CHANGED,
G_CALLBACK(omp_editor_page_update_track_info), NULL);
+ g_signal_connect(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_COUNT_CHANGED,
+ G_CALLBACK(omp_editor_page_update_track_count), NULL);
+
return main_vbox;
}
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -24,18 +24,476 @@
* Playlist editor, part 2: file adding window
*/
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+#include <glib/gi18n.h>
+#include <libmokoui2/moko-finger-scroll.h>
+#include <string.h>
+
#include "files_page.h"
+#include "guitools.h"
+#include "persistent.h"
+#include "playlist.h"
+/// Enumeration of the file list columns
+enum
+{
+ ICON_COLUMN,
+ NAME_COLUMN,
+ ACT_ADD_COLUMN,
+ COLUMN_COUNT
+};
+
+/// Enumeration of the types the list entries may get assigned
+enum
+{
+ UNPLAYABLE_TYPE,
+ FILE_TYPE,
+ DIRECTORY_TYPE,
+ MP3_TYPE,
+ OGG_TYPE,
+ TYPE_COUNT
+};
+
+/// Array holding the icons' GdkPixbufs so we can assign them to the list view rows
+GdkPixbuf *omp_files_page_type_icons[TYPE_COUNT];
+
+/// Array holding the file extensions the icons depict
+gchar *omp_files_page_type_extensions[TYPE_COUNT];
+
+/// Hash table allowing matching of file extensions to icons
+GHashTable *omp_files_page_type_table = NULL;
+
+/// List store for the file selector
+GtkListStore *omp_files_page_list_store = NULL;
+
+/// The label showing the current file system path
+GtkWidget *omp_files_path_label = NULL;
+
+
+
/**
+ * Finds a given file's extension and returns a pointer to its first char
+ * @return A pointer to the first char of the extension, belongs to original string so do not free
+ * @todo Make unicode safe?
+ */
+gchar *
+get_file_extension(gchar *file_name)
+{
+ guint i;
+
+ g_return_val_if_fail(file_name, NULL);
+
+ for (i=strlen(file_name); (i>0) && (file_name[i]!='.'); i--);
+
+ return file_name+i+1;
+}
+
+/**
+ * Confirms to the user that the files have been added successfully
+ * @param track_count Number of tracks that were added
+ * @note We only use this when adding directories as it would be annoying otherwise
+ */
+void
+omp_files_page_success_report(guint track_count)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new(0,
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
+ _("Successfully added %d files"), track_count);
+
+ // We don't want a title of "<unnamed>"
+ gtk_window_set_title(GTK_WINDOW(dialog), " ");
+
+ g_signal_connect_swapped(dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
+ gtk_widget_show_all(dialog);
+}
+
+/**
+ * Moves one level upwards in the directory hierarchy
+ * @todo Unicode compatibility
+ */
+void
+omp_files_page_set_prev_dir(GtkButton *button, gpointer user_data)
+{
+ gchar *new_path;
+ guint i;
+
+ new_path = g_strdup(omp_session_get_file_chooser_path());
+
+ // Find last directory level and remove it
+ for (i=strlen(new_path); (i>0) && (new_path[i] != '/'); i--);
+
+ if (new_path[i] == '/')
+ {
+ // Root directory is handled differently
+ if (i == 0)
+ {
+ new_path[1] = 0; // Directory becomes '/'
+ } else {
+ new_path[i] = 0; // Last directory gets cut off
+ }
+
+ omp_session_set_file_chooser_path(new_path);
+ omp_files_page_update_path();
+ }
+
+ g_free(new_path);
+}
+
+/**
+ * Reads the directory contents of the current path and updates the view's model accordingly
+ */
+void
+omp_files_page_update_path()
+{
+ gchar *path, *dir_entry, *dir_entry_abs, *temp;
+ GDir *dir;
+ GError *error;
+ GtkTreeIter iterator;
+ GdkPixbuf *icon;
+
+ gtk_list_store_clear(omp_files_page_list_store);
+
+ path = omp_session_get_file_chooser_path();
+ gtk_label_set_text(GTK_LABEL(omp_files_path_label), path);
+
+ if (path[0] == 0) return;
+ dir = g_dir_open(path, 0, &error);
+
+ if (!dir)
+ {
+ g_printerr("Could not read directory %s: %s\n", path, error->message);
+ temp = g_strdup_printf(_("Could not read directory: %s"), error->message);
+ error_dialog(temp);
+ g_free(temp);
+
+ g_error_free(error);
+ g_free(path);
+ return;
+ }
+
+ do
+ {
+ dir_entry = (gchar*)g_dir_read_name(dir);
+ icon = NULL;
+
+ if (!dir_entry) break;
+
+ // Skip hidden entries
+ if (dir_entry[0] == '.') continue;
+
+ // Do we need the directory icon?
+ dir_entry_abs = g_build_path("/", path, dir_entry, NULL);
+ if (g_file_test(dir_entry_abs, G_FILE_TEST_IS_DIR))
+ {
+ icon = omp_files_page_type_icons[DIRECTORY_TYPE];
+ }
+ g_free(dir_entry_abs);
+
+ // Determine icon through file extension
+ if (!icon)
+ {
+ temp = g_ascii_strdown(get_file_extension(dir_entry), -1);
+ icon = g_hash_table_lookup(omp_files_page_type_table, temp);
+ g_free(temp);
+ }
+
+ if (!icon)
+ icon = omp_files_page_type_icons[UNPLAYABLE_TYPE];
+
+ // Add entry to list
+ gtk_list_store_append(omp_files_page_list_store, &iterator);
+ gtk_list_store_set(omp_files_page_list_store, &iterator,
+ ICON_COLUMN, icon,
+ NAME_COLUMN, dir_entry, -1);
+
+ } while (TRUE);
+
+ g_dir_close(dir);
+ g_free(path);
+}
+
+/**
+ * Monitors general click events on the list view and acts appropriately
+ */
+gboolean
+omp_files_page_list_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+ GtkTreePath *tree_path;
+ GtkTreeViewColumn *tree_column;
+ GtkTreeIter iterator;
+ GtkTreeModel *model;
+ GList *columns;
+ gint column_id;
+ gchar *entry_name, *entry_name_abs;
+ GdkPixbuf *icon;
+
+ g_return_val_if_fail(GTK_IS_TREE_VIEW(widget), TRUE);
+
+ // Find colum that was hit
+ gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), event->x, event->y,
+ &tree_path, &tree_column, NULL, NULL);
+ if (!tree_path) return TRUE;
+
+ columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(widget));
+ column_id = g_list_index(columns, (gpointer)tree_column);
+ g_list_free(columns);
+
+ // Find row that was hit
+ model = GTK_TREE_MODEL(gtk_tree_view_get_model(GTK_TREE_VIEW(widget)));
+ gtk_tree_model_get_iter(model, &iterator, tree_path);
+
+ // Select row so the selection gets updated right now
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tree_path, NULL, FALSE);
+
+ // Get file/dir name
+ gtk_tree_model_get(model, &iterator,
+ ICON_COLUMN, &icon,
+ NAME_COLUMN, &entry_name, -1);
+
+ entry_name_abs =
+ g_build_filename(omp_session_get_file_chooser_path(), entry_name, NULL);
+
+ // Determine what to do
+ switch (column_id)
+ {
+ case NAME_COLUMN:
+ {
+ // Enter directory if entry is one
+ if (icon == omp_files_page_type_icons[DIRECTORY_TYPE])
+ {
+ omp_session_set_file_chooser_path(entry_name_abs);
+ omp_files_page_update_path();
+ }
+
+ break;
+ }
+
+ case ACT_ADD_COLUMN:
+ {
+ // Add dir/file
+ if (icon == omp_files_page_type_icons[DIRECTORY_TYPE])
+ {
+ omp_files_page_success_report(
+ omp_playlist_track_append_directory(entry_name_abs));
+
+ } else {
+
+ omp_playlist_track_append_file(entry_name_abs);
+ }
+
+ // Save playlist
+ omp_playlist_save();
+
+ break;
+ }
+ }
+
+ // Clean up
+ g_free(entry_name);
+ g_free(entry_name_abs);
+ gtk_tree_path_free(tree_path);
+
+ return TRUE;
+}
+
+/**
+ * Compare function to determine sort order for the file list view
+ */
+gint
+omp_files_page_view_compare_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
+ gpointer userdata)
+{
+ gchar *entry1, *entry2;
+ GdkPixbuf *icon1, *icon2;
+ gint order;
+
+ // Directories come before files
+ gtk_tree_model_get(model, a, ICON_COLUMN, &icon1, -1);
+ gtk_tree_model_get(model, b, ICON_COLUMN, &icon2, -1);
+
+ if ( (icon1 == omp_files_page_type_icons[DIRECTORY_TYPE]) ||
+ (icon2 == omp_files_page_type_icons[DIRECTORY_TYPE]) )
+ {
+ // Look at the names if both are directories
+ if (icon1 == icon2)
+ {
+ gtk_tree_model_get(model, a, NAME_COLUMN, &entry1, -1);
+ gtk_tree_model_get(model, b, NAME_COLUMN, &entry2, -1);
+ order = g_utf8_collate(entry1, entry2);
+ g_free(entry1);
+ g_free(entry2);
+
+ } else {
+
+ // One is a dir and one is not, so no need to look at names
+ order = (icon1 == omp_files_page_type_icons[DIRECTORY_TYPE]) ? -1 : 1;
+ }
+
+ } else {
+
+ // Neither entry is a directory, so sort by name
+ gtk_tree_model_get(model, a, NAME_COLUMN, &entry1, -1);
+ gtk_tree_model_get(model, b, NAME_COLUMN, &entry2, -1);
+ order = g_utf8_collate(entry1, entry2);
+ g_free(entry1);
+ g_free(entry2);
+ }
+
+ return order;
+}
+
+/**
+ * Sets up the icons and file extensions used for distinguishing files in the list view
+ */
+void
+omp_files_page_type_setup()
+{
+ // Load file type icons
+ omp_files_page_type_icons[UNPLAYABLE_TYPE] =
+ pixbuf_new_from_file("ico-filetype-unplayable.png");
+
+ omp_files_page_type_icons[FILE_TYPE] =
+ pixbuf_new_from_file("ico-filetype-generic.png");
+
+ omp_files_page_type_icons[DIRECTORY_TYPE] =
+ gtk_widget_render_icon(GTK_WIDGET(omp_window), "gtk-directory",
+ GTK_ICON_SIZE_BUTTON, NULL);
+
+ omp_files_page_type_icons[MP3_TYPE] =
+ pixbuf_new_from_file("ico-filetype-mp3.png");
+
+ omp_files_page_type_icons[OGG_TYPE] =
+ pixbuf_new_from_file("ico-filetype-ogg.png");
+
+ // Fill file extension array
+ omp_files_page_type_extensions[MP3_TYPE] = g_strdup("mp3");
+ omp_files_page_type_extensions[OGG_TYPE] = g_strdup("ogg");
+
+ // Create and fill type hash table
+ omp_files_page_type_table = g_hash_table_new(g_str_hash, g_str_equal);
+
+ g_hash_table_insert(omp_files_page_type_table,
+ omp_files_page_type_extensions[MP3_TYPE], omp_files_page_type_icons[MP3_TYPE]);
+
+ g_hash_table_insert(omp_files_page_type_table,
+ omp_files_page_type_extensions[OGG_TYPE], omp_files_page_type_icons[OGG_TYPE]);
+}
+
+/**
+ * Creates the file view
+ * @param container Destination container of the view
+ */
+void
+omp_files_page_list_create(GtkContainer *container)
+{
+ GtkWidget *tree_view;
+ GtkTreeSelection *select;
+ GtkTreeSortable *sortable;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ // Create data model
+ omp_files_page_list_store = gtk_list_store_new(COLUMN_COUNT,
+ GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+ // Set up sorting
+ sortable = GTK_TREE_SORTABLE(omp_files_page_list_store);
+ gtk_tree_sortable_set_sort_func(sortable, 0, omp_files_page_view_compare_func, 0, NULL);
+ gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING);
+
+ // Create data view
+ tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(omp_files_page_list_store));
+ g_object_unref(G_OBJECT(omp_files_page_list_store));
+
+ g_signal_connect(G_OBJECT(tree_view), "button-press-event",
+ G_CALLBACK(omp_files_page_list_clicked), NULL);
+
+ // Configure selection handler
+ select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
+ gtk_tree_selection_set_mode(GTK_TREE_SELECTION(select), GTK_SELECTION_SINGLE);
+
+ // Set up columns
+ renderer = gtk_cell_renderer_pixbuf_new();
+ column = gtk_tree_view_column_new_with_attributes("", renderer,
+ "pixbuf", ICON_COLUMN, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", 1, NULL);
+ column = gtk_tree_view_column_new_with_attributes(_("File/Folder Name"), renderer,
+ "text", NAME_COLUMN, NULL);
+ gtk_tree_view_column_set_expand(column, TRUE);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+
+ renderer = gtk_cell_renderer_pixbuf_new();
+ g_object_set(G_OBJECT(renderer), "stock-id", "gtk-add", NULL);
+ column = gtk_tree_view_column_new_with_attributes("", renderer, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+
+ // Add file view to container
+ gtk_container_add(container, GTK_WIDGET(tree_view));
+}
+
+/**
* Creates the file chooser UI page and all its elements
*/
GtkWidget *
omp_files_page_create()
{
- GtkWidget *main_vbox;
+ GtkWidget *main_vbox, *alignment, *label, *scroll_box, *hbox, *button, *image;
// Create main container
main_vbox = gtk_vbox_new(FALSE, 0);
+ // HBox containing "back" button and path label
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(main_vbox), GTK_WIDGET(hbox), FALSE, FALSE, 0);
+
+ button = gtk_button_new();
+ image = gtk_image_new_from_icon_name("gtk-undo-ltr", GTK_ICON_SIZE_MENU);
+ gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
+
+ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(omp_files_page_set_prev_dir), NULL);
+
+ alignment = label_create(&label, "Sans 6", "black", 0, 0, 0, 0, 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 5, 5, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(alignment), FALSE, FALSE, 0);
+ omp_files_path_label = label;
+
+ // File list viewport
+ scroll_box = moko_finger_scroll_new();
+ gtk_box_pack_start(GTK_BOX(main_vbox), GTK_WIDGET(scroll_box), TRUE, TRUE, 0);
+
+ // Set up file types we distinguish
+ omp_files_page_type_setup();
+
+ // Create and populate file view
+ omp_files_page_list_create(GTK_CONTAINER(scroll_box));
+
+ // Make all widgets visible
+ gtk_widget_show_all(main_vbox);
+
return main_vbox;
}
+
+/**
+ * Frees resources used by the file chooser UI
+ */
+void
+omp_files_page_free()
+{
+ guint i;
+
+ g_hash_table_destroy(omp_files_page_type_table);
+
+ for (i=0; i<TYPE_COUNT; i++)
+ if (omp_files_page_type_extensions[i])
+ g_free(omp_files_page_type_extensions[i]);
+
+ for (i=0; i<TYPE_COUNT; i++)
+ g_object_unref(omp_files_page_type_icons[i]);
+}
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.h 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.h 2007-09-11 09:00:58 UTC (rev 2949)
@@ -30,7 +30,10 @@
#include <gtk/gtk.h>
GtkWidget *omp_files_page_create();
+void omp_files_page_free();
+void omp_files_page_update_path();
+
#endif
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -35,6 +35,7 @@
/**
* Loads an image from a file into a pixel buffer
+ * @return Pixbuf with the image, must be unref'd after use
*/
GdkPixbuf*
pixbuf_new_from_file(const gchar *file_name)
@@ -177,7 +178,7 @@
* Adds a child to a GtkNotebook, filling the page handle with a stock icon
*/
void
-notebook_add_page_with_icon(GtkWidget *notebook, GtkWidget *child, const gchar *icon_name, int padding)
+notebook_add_page_with_stock(GtkWidget *notebook, GtkWidget *child, const gchar *icon_name, int padding)
{
GtkWidget *icon, *alignment;
@@ -192,3 +193,24 @@
gtk_container_child_set(GTK_CONTAINER(notebook), child, "tab-expand", TRUE, NULL);
}
+/**
+ * Adds a child to a GtkNotebook, filling the page handle with an application-specific image
+ */
+void
+notebook_add_page_with_image(GtkWidget *notebook, GtkWidget *child, const gchar *image_name, int padding)
+{
+ gchar *image_file_name;
+ GtkWidget *icon, *alignment;
+
+ image_file_name = g_build_path("/", ui_image_path, image_name, NULL);
+ icon = gtk_image_new_from_file(image_file_name);
+ g_free(image_file_name);
+
+ alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), padding, padding, padding, padding);
+ gtk_container_add(GTK_CONTAINER(alignment), icon);
+ gtk_widget_show_all(GTK_WIDGET(alignment));
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), child, alignment);
+ gtk_container_child_set(GTK_CONTAINER(notebook), child, "tab-expand", TRUE, NULL);
+}
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.h 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.h 2007-09-11 09:00:58 UTC (rev 2949)
@@ -44,6 +44,7 @@
void container_add_image_with_ref(GtkContainer *container, gchar *image_name, GtkWidget **image);
void container_add_image(GtkContainer *container, gchar *image_name);
-void notebook_add_page_with_icon(GtkWidget *notebook, GtkWidget *child, const gchar *icon_name, int padding);
+void notebook_add_page_with_stock(GtkWidget *notebook, GtkWidget *child, const gchar *icon_name, int padding);
+void notebook_add_page_with_image(GtkWidget *notebook, GtkWidget *child, const gchar *image_name, int padding);
#endif
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -252,28 +252,37 @@
// Add main page
page = omp_main_page_create();
- notebook_add_page_with_icon(omp_notebook, page, MOKO_STOCK_SPEAKER, 0);
+ notebook_add_page_with_stock(omp_notebook, page, MOKO_STOCK_SPEAKER, 0);
omp_notebook_tabs[OMP_TAB_MAIN] = page;
// Add playlist page
page = omp_playlist_page_create();
- notebook_add_page_with_icon(omp_notebook, page, MOKO_STOCK_VIEW, 0);
+ notebook_add_page_with_image(omp_notebook, page, "ico-playlists.png", 0);
omp_notebook_tabs[OMP_TAB_PLAYLISTS] = page;
// Add playlist editor page
page = omp_editor_page_create();
- notebook_add_page_with_icon(omp_notebook, page, "gtk-index", 0);
+ notebook_add_page_with_image(omp_notebook, page, "ico-playlist-editor.png", 0);
omp_notebook_tabs[OMP_TAB_PLAYLIST_EDITOR] = page;
gtk_widget_hide(page); // We show the page once a playlist was loaded
// Add file chooser page
page = omp_files_page_create();
- notebook_add_page_with_icon(omp_notebook, page, "gtk-index", 0);
+ notebook_add_page_with_image(omp_notebook, page, "ico-file-chooser.png", 0);
omp_notebook_tabs[OMP_TAB_FILE_CHOOSER] = page;
gtk_widget_hide(page); // We show the page once user wants to add files
}
/**
+ * Lets all UI pages clean up
+ */
+void
+omp_window_free_pages()
+{
+ omp_files_page_free();
+}
+
+/**
* Displays the main window and all widgets it contains
*/
void
@@ -288,7 +297,7 @@
* @see omp_notebook_tabs
*/
void
-omp_show_tab(guint tab_id)
+omp_tab_show(guint tab_id)
{
g_return_if_fail(tab_id < OMP_TABS);
@@ -301,7 +310,7 @@
* @see omp_notebook_tabs
*/
void
-omp_hide_tab(guint tab_id)
+omp_tab_hide(guint tab_id)
{
g_return_if_fail(tab_id < OMP_TABS);
@@ -309,6 +318,17 @@
}
/**
+ *
+ */
+void
+omp_tab_focus(guint tab_id)
+{
+ g_return_if_fail(tab_id < OMP_TABS);
+
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(omp_notebook), tab_id);
+}
+
+/**
* If only I knew what this is
*/
gint
@@ -379,7 +399,8 @@
signal(SIGSEGV, handler_sigsegfault);
signal(SIGUSR1, handler_sigusr1);
- // Initialize playback, playlist and UI handling
+ // Initialize backends and user interfaces
+ omp_session_init();
omp_config_init();
omp_window_create();
if (!omp_playback_init()) return EXIT_FAILURE;
@@ -395,6 +416,7 @@
gtk_main();
// Clean up
+ omp_window_free_pages();
omp_playback_save_state();
omp_playback_free();
omp_playlist_free();
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h 2007-09-11 09:00:58 UTC (rev 2949)
@@ -52,7 +52,8 @@
void omp_application_terminate();
-void omp_show_tab(guint tab_id);
-void omp_hide_tab(guint tab_id);
+void omp_tab_show(guint tab_id);
+void omp_tab_hide(guint tab_id);
+void omp_tab_focus(guint tab_id);
#endif
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -60,10 +60,14 @@
GtkWidget *omp_main_window = NULL;
-gboolean omp_main_time_slider_can_update = TRUE; ///< Determines whether the time slider can be updated or not
-gboolean omp_main_time_slider_was_dragged = FALSE; ///< Is toggled after the user finished dragging the time slider's button
+/// Determines whether the time slider can be updated or not
+gboolean omp_main_time_slider_can_update = TRUE;
+/// Is toggled after the user finished dragging the time slider's button
+gboolean omp_main_time_slider_was_dragged = FALSE;
+
// Forward declarations for internal use
+void omp_main_playlist_loaded(gpointer instance, gchar *title, gpointer user_data);
void omp_main_update_track_change(gpointer instance, gpointer user_data);
void omp_main_update_track_info_changed(gpointer instance, guint track_id, gpointer user_data);
void omp_main_update_shuffle_state(gpointer instance, gboolean state, gpointer user_data);
@@ -586,6 +590,9 @@
// Set up playlist signal handlers
+ g_signal_connect(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_LOADED,
+ G_CALLBACK(omp_main_playlist_loaded), NULL);
+
g_signal_connect(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED,
G_CALLBACK(omp_main_update_track_change), NULL);
@@ -622,6 +629,16 @@
}
/**
+ * Callback for the "playlist loaded" event
+ */
+void
+omp_main_playlist_loaded(gpointer instance, gchar *list_title, gpointer user_data)
+{
+ // Playlist editor can now be used
+ omp_tab_show(OMP_TAB_PLAYLIST_EDITOR);
+}
+
+/**
* Evaluates current track information and updates the config/UI if necessary
* @note This function only checks elements that don't change too often
* @note For the rest we have specialized functions below
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -34,8 +34,9 @@
#include <fcntl.h>
#include <unistd.h>
+#include "files_page.h"
+#include "main.h"
#include "persistent.h"
-#include "main.h"
#include "playlist.h"
#include "playback.h"
@@ -59,7 +60,7 @@
/**
- * Load application configuration data
+ * Initalize and load application configuration data
*/
void
omp_config_init()
@@ -169,9 +170,33 @@
omp_session->volume = 100;
omp_session->fade_speed = 5000;
+ g_snprintf(omp_session->file_chooser_path, sizeof(omp_session->file_chooser_path),
+ "%s", "/home/abraxa/local_nas/audio/mp3s/");
}
/**
+ * Initialize the session handling mechanism
+ */
+void
+omp_session_init()
+{
+ // This mustn't be called more than once
+ g_return_if_fail(omp_session == NULL);
+
+ omp_session = g_new0(struct _omp_session, 1);
+ omp_session_reset();
+}
+
+/**
+ * Frees the resources used for session data
+ */
+void
+omp_session_free()
+{
+ g_free(omp_session);
+}
+
+/**
* Restores program state from last session
*/
void
@@ -181,11 +206,6 @@
g_print("Loading session data\n");
#endif
- // This mustn't be called more than once
- g_assert(omp_session == NULL);
-
- omp_session = g_new0(struct _omp_session, 1);
-
// Load config
omp_session_load();
@@ -218,15 +238,9 @@
omp_playback_set_track_position(omp_session->track_position);
}
-}
-/**
- * Free resources used for session data
- */
-void
-omp_session_free()
-{
- g_free(omp_session);
+ // Restore various states
+ omp_files_page_update_path();
}
/**
@@ -238,6 +252,8 @@
gint session_file, result;
gchar *file_name;
+ g_return_if_fail(omp_session);
+
// SESSION_FILE_NAME is relative to user's home dir
file_name = g_build_filename(g_get_home_dir(), SESSION_FILE_NAME, NULL);
@@ -272,6 +288,8 @@
gint session_file, result;
gchar *file_name;
+ g_return_if_fail(omp_session);
+
// SESSION_FILE_NAME is relative to user's home dir
file_name = g_build_filename(g_get_home_dir(), SESSION_FILE_NAME, NULL);
@@ -306,6 +324,8 @@
void
omp_session_set_playback_state(glong track_position, gboolean is_playing)
{
+ g_return_if_fail(omp_session);
+
omp_session->track_position = track_position;
omp_session->was_playing = is_playing;
@@ -318,6 +338,8 @@
void
omp_session_set_playlist(gchar *playlist_file)
{
+ g_return_if_fail(omp_session);
+
g_snprintf(omp_session->playlist_file, sizeof(omp_session->playlist_file), "%s", playlist_file);
omp_session_save();
}
@@ -328,6 +350,8 @@
void
omp_session_set_track_id(guint track_id)
{
+ g_return_if_fail(omp_session);
+
omp_session->playlist_position = track_id;
omp_session_save();
}
@@ -338,15 +362,44 @@
void
omp_session_set_volume(guint volume)
{
+ g_return_if_fail(omp_session);
+
omp_session->volume = volume;
omp_session_save();
}
/**
+ * Set path to be used for the file chooser UI
+ */
+void
+omp_session_set_file_chooser_path(gchar *path)
+{
+ g_return_if_fail(omp_session);
+
+ g_snprintf(omp_session->file_chooser_path, sizeof(omp_session->file_chooser_path),
+ "%s", path);
+
+ // We don't save the session immediately - saving at app termination is good enough
+}
+
+/**
* Returns the number of milliseconds defining the duration of a volume fade
*/
guint
omp_session_get_fade_speed()
{
+ g_return_val_if_fail(omp_session, 0);
+
return omp_session->fade_speed;
}
+
+/**
+ * Returns the path used for the file chooser UI; must be freed after use
+ */
+gchar *
+omp_session_get_file_chooser_path()
+{
+ g_return_val_if_fail(omp_session, NULL);
+
+ return g_strdup((gchar *)&omp_session->file_chooser_path);
+}
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h 2007-09-11 09:00:58 UTC (rev 2949)
@@ -33,6 +33,8 @@
#define OMP_EVENT_CONFIG_SHUFFLE_STATE_CHANGED "config_shuffle_state_changed"
#define OMP_EVENT_CONFIG_REPEAT_MODE_CHANGED "config_repeat_mode_changed"
+#define OMP_EVENT_SESSION_FILE_CHOOSER_PATH_CHANGED "session_file_chooser_path_changed"
+
/// Application configuration data
/// @note Default values are taken from omp_default_config
/// @note Update that struct as well if you make changes here!
@@ -57,7 +59,7 @@
guint playlist_position; ///< Position within the playlist
gulong track_position; ///< Position to resume playback from within the last played track
gboolean was_playing; ///< Set to TRUE of track was being played as the player was closed
- gchar filesel_path[256]; ///< Last path used in the file selection dialog
+ gchar file_chooser_path[256]; ///< Last path used in the file selection dialog
gchar playlist_file[256]; ///< Path and file name of current (=last used) playlist
};
@@ -76,8 +78,9 @@
guint omp_config_get_prev_track_treshold();
+void omp_session_init();
+void omp_session_free();
void omp_session_restore_state();
-void omp_session_free();
void omp_session_save();
void omp_session_load();
@@ -85,7 +88,9 @@
void omp_session_set_playlist(gchar *playlist_file);
void omp_session_set_track_id(guint track_id);
void omp_session_set_volume(guint volume);
+void omp_session_set_file_chooser_path(gchar *path);
guint omp_session_get_fade_speed();
+gchar *omp_session_get_file_chooser_path();
#endif
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -36,6 +36,9 @@
/// Our ticket to the gstreamer world
GstElement *omp_gst_playbin = NULL;
+/// gstreamer audio output element
+GstElement *omp_gst_audiosink = NULL;
+
/// Handle of the UI-updating timeout
guint omp_playback_ui_timeout = 0;
@@ -105,16 +108,21 @@
G_SIGNAL_RUN_FIRST, 0, 0, NULL, g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
+ // Create gstreamer audio sink
+ omp_gst_audiosink = gst_element_factory_make("alsasink", NULL);
+
// Set up gstreamer pipe and bins
- omp_gst_playbin = gst_element_factory_make("playbin", "play");
+ omp_gst_playbin = gst_element_factory_make("playbin", NULL);
- if (!omp_gst_playbin)
+ if ( (!omp_gst_audiosink) || (!omp_gst_playbin) )
{
- error_dialog(_("Error: gstreamer failed to initialize.\nPlease make sure gstreamer and its modules are properly installed."));
+ error_dialog(_("Error: gstreamer failed to initialize.\nPlease make sure gstreamer and its modules are properly installed (esp. gst-meta-audio)."));
return FALSE;
}
+ g_object_set(G_OBJECT(omp_gst_playbin), "audio-sink", omp_gst_audiosink, NULL);
+
// Set up message hooks
bus = gst_pipeline_get_bus(GST_PIPELINE(omp_gst_playbin));
@@ -149,6 +157,8 @@
gst_element_set_state(omp_gst_playbin, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(omp_gst_playbin));
+
+ gst_object_unref(GST_OBJECT(omp_gst_audiosink));
}
/**
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -31,6 +31,7 @@
#include <glib/gstdio.h>
#include <uriparser/Uri.h>
+#include <stdarg.h>
#include <string.h>
#include "playlist.h"
@@ -52,6 +53,9 @@
/// Current track's data
omp_spiff_track *omp_playlist_current_track = NULL;
+/// Pointer to the last track of the playlist (saves time when appending tracks)
+omp_spiff_track *omp_playlist_last_track = NULL;
+
/// Numerical id of the current track within the playlist
guint omp_playlist_current_track_id = -1;
@@ -175,6 +179,7 @@
omp_playback_reset();
omp_playlist_current_track_id = 0;
omp_playlist_current_track = omp_playlist->tracks;
+ omp_playlist_last_track = NULL;
if (omp_playlist_current_track)
{
@@ -189,13 +194,11 @@
g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_LOADED, title);
g_free(title);
- // Show playlist editor
- omp_show_tab(OMP_TAB_PLAYLIST_EDITOR);
-
} else {
omp_playlist_current_track_id = -1;
omp_playlist_current_track = NULL;
+ omp_playlist_last_track = NULL;
#ifdef DEBUG
g_printerr("Could not load playlist: %s\n", playlist_file);
@@ -621,7 +624,7 @@
* @todo Unicode support
*/
void
-omp_playlist_set_preliminary_metadata(gchar *track_uri)
+omp_playlist_set_preliminary_metadata(omp_spiff_track *track, gchar *track_uri)
{
UriParserStateA state;
UriUriA uri;
@@ -630,7 +633,7 @@
state.uri = &uri;
- g_return_if_fail(omp_playlist_current_track);
+ g_return_if_fail(track);
if (uriParseUriA(&state, track_uri) != 0)
{
@@ -642,19 +645,33 @@
// The last part of the URI path is the file name of the request - which we want
segment = uri.pathTail;
+
+ if (!segment)
+ {
+ uriFreeUriMembersA(&uri);
+ #ifdef DEBUG
+ g_printerr("UriParser did not deliver path tail for %s\n", track_uri);
+ #endif
+ return;
+ }
+
+ if (!segment->text.first)
+ {
+ uriFreeUriMembersA(&uri);
+ #ifdef DEBUG
+ g_printerr("UriParser did not deliver first text element for %s\n", track_uri);
+ #endif
+ return;
+ }
+
title = get_base_file_name((gchar*)segment->text.first);
uriUnescapeInPlaceA(title);
// Set preliminary metadata if necessary
- if (!omp_playlist_current_track->title)
+ if (!track->title)
{
- omp_playlist_current_track->title = g_strdup(title);
- omp_playlist_current_track->title_is_preliminary = TRUE;
- omp_playlist_save();
-
- // Notify UI of the change
- g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_INFO_CHANGED,
- omp_playlist_current_track_id);
+ track->title = g_strdup(title);
+ track->title_is_preliminary = TRUE;
}
g_free(title);
@@ -722,8 +739,12 @@
omp_playlist_update_track_duration();
// Obtain preliminary track title from URI if needed
- omp_playlist_set_preliminary_metadata(track_uri);
+ omp_playlist_set_preliminary_metadata(omp_playlist_current_track, track_uri);
+ // Notify UI of the metadata change
+ g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_INFO_CHANGED,
+ omp_playlist_current_track_id);
+
g_free(track_uri);
return track_loaded;
@@ -768,16 +789,24 @@
void
omp_playlist_update_track_count()
{
- omp_spiff_track *track;
- gint tracks = 0;
+ omp_spiff_track *track, *last_track = NULL;
+ gint old_count, count = 0;
if (!omp_playlist) return;
- for (track=omp_playlist->tracks; track!=NULL; track=track->next, tracks++);
+ old_count = omp_playlist_track_count;
- omp_playlist_track_count = tracks;
+ // Walk through the entire list to count number of tracks and find last track pointer
+ for (track=omp_playlist->tracks; track!=NULL; last_track=track, track=track->next, count++);
- g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_COUNT_CHANGED);
+ omp_playlist_track_count = count;
+ omp_playlist_last_track = last_track;
+
+ // Notify UI only if track count actually changed
+ if (old_count != count)
+ {
+ g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_COUNT_CHANGED);
+ }
}
/**
@@ -875,6 +904,136 @@
}
/**
+ * Appends a track to the end of the playlist
+ * @todo Make unicode-safe
+ */
+void
+omp_playlist_track_append_file(gchar *file_name)
+{
+ omp_spiff_track *new_track;
+ omp_spiff_mvalue *location;
+ gchar *uri, name_char;
+ guint name_pos, uri_pos, name_len;
+
+ if (!omp_playlist) return;
+ if (!file_name) return;
+
+ // Try to make the "last track" pointer valid - if it stays NULL then the list is empty
+ if (!omp_playlist_last_track)
+ {
+ omp_playlist_update_track_count();
+ }
+
+ // Append track
+ if (omp_playlist_last_track)
+ {
+ new_track = omp_spiff_new_track_before(&omp_playlist_last_track->next);
+ omp_playlist_last_track = omp_playlist_last_track->next;
+ } else {
+ new_track = omp_spiff_new_track_before(&omp_playlist->tracks);
+ omp_playlist_last_track = omp_playlist->tracks;
+ }
+
+ location = omp_spiff_new_mvalue_before(&new_track->locations);
+ omp_playlist_track_count++;
+
+ // Build URI for the file location
+ name_len = strlen(file_name);
+ uri = g_malloc(7+3*name_len); // Enough for worst case: every char becomes %xx character sequence
+
+ g_sprintf(uri, "file://");
+ uri_pos = 7;
+
+ // We could use uriEscapeA() here but that will also transform '/' to %2F, which we do not want
+ for (name_pos=0; name_pos < name_len; name_pos++)
+ {
+ name_char = file_name[name_pos];
+ if ( ((name_char >= 'a') && (name_char <= 'z'))
+ || ((name_char >= 'A') && (name_char <= 'Z'))
+ || ((name_char >= '0') && (name_char <= '9'))
+ || (name_char == '-') || (name_char == '.')
+ || (name_char == '_') || (name_char == '~')
+ || (name_char == '/') )
+ {
+ uri[uri_pos++] = name_char;
+
+ } else {
+
+ uri[uri_pos+0] = '%';
+ uri[uri_pos+1] = uriHexToLetterA(name_char >> 4);
+ uri[uri_pos+2] = uriHexToLetterA(name_char & 0x0F);
+ uri_pos += 3;
+ }
+ }
+ uri[uri_pos] = 0;
+
+ location->value = g_strdup(uri);
+ g_free(uri);
+
+ // Give the track list something to show
+ omp_playlist_last_track->title = get_base_file_name(file_name);
+ omp_playlist_last_track->title_is_preliminary = TRUE;
+
+ // Notify UI of the change
+ g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_COUNT_CHANGED);
+}
+
+/**
+ * Recursively adds all files from a directory and its subdirectories
+ * @param dir_name Directory to add
+ * @return Number of files added
+ */
+guint
+omp_playlist_track_append_directory(gchar *dir_name)
+{
+ gchar *dir_entry, *dir_entry_abs, *temp;
+ GDir *dir;
+ GError *error;
+ guint file_count = 0;
+
+ g_return_val_if_fail(dir_name, 0);
+
+ dir = g_dir_open(dir_name, 0, &error);
+
+ if (!dir)
+ {
+ g_printerr("Could not read directory %s: %s\n", dir_name, error->message);
+ temp = g_strdup_printf(_("Could not read directory: %s"), error->message);
+ error_dialog(temp);
+ g_free(temp);
+
+ g_error_free(error);
+ return 0;
+ }
+
+ do
+ {
+ dir_entry = (gchar*)g_dir_read_name(dir);
+
+ if (!dir_entry) break;
+
+ // Skip hidden entries
+ if (dir_entry[0] == '.') continue;
+
+ // Do we need to dive into a subdirectory?
+ dir_entry_abs = g_build_path("/", dir_name, dir_entry, NULL);
+ if (g_file_test(dir_entry_abs, G_FILE_TEST_IS_DIR))
+ {
+ file_count += omp_playlist_track_append_directory(dir_entry_abs);
+ } else {
+ omp_playlist_track_append_file(dir_entry_abs);
+ file_count++;
+ }
+ g_free(dir_entry_abs);
+
+ } while (TRUE);
+
+ g_dir_close(dir);
+
+ return file_count;
+}
+
+/**
* Utility function that removes the path and extension of a file name
* @param file_name File name to extract title from, can contain a path
* @return String holding the title, must be freed after use
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h 2007-09-11 09:00:58 UTC (rev 2949)
@@ -92,7 +92,13 @@
void omp_playlist_advance_iter(omp_playlist_iter *iter);
gboolean omp_playlist_iter_finished(omp_playlist_iter *iter);
+void omp_playlist_track_append_file(gchar *file_name);
+guint omp_playlist_track_append_directory(gchar *dir_name);
+
gchar *get_base_file_name(gchar *file_name);
gchar *get_playlist_title(gchar *playlist_file);
+// Taken from uriparser's UriCommon.h, which sadly is not installed with uriparser
+char uriHexToLetterA(unsigned int value);
+
#endif
Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.c 2007-09-11 05:07:26 UTC (rev 2948)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.c 2007-09-11 09:00:58 UTC (rev 2949)
@@ -24,6 +24,7 @@
* Playlist UI handling
*/
+#include <glib/gprintf.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <libmokoui2/moko-finger-scroll.h>
@@ -31,12 +32,12 @@
#include <string.h>
-#include "playlist_page.h"
+#include "guitools.h"
#include "main.h"
-#include "guitools.h"
#include "playlist.h"
+#include "playlist_page.h"
-/// Enumeration for the playlist list columns
+/// Enumeration of the playlist list columns
enum
{
TYPE_COLUMN,
@@ -180,6 +181,8 @@
// Clean up
g_free(playlist_file_abs);
+ g_free(playlist_file);
+ g_free(playlist_name);
gtk_tree_path_free(tree_path);
return TRUE;
@@ -194,7 +197,7 @@
gchar *path, *file_name;
const gchar *name = gtk_entry_get_text(GTK_ENTRY(omp_playlist_page_entry));
- g_return_if_fail(strcmp(name, "") != 0);
+ g_return_if_fail(name[0] != 0);
// Playlist path is relative to user's home dir
path = g_build_path("/", g_get_home_dir(), RELATIVE_PLAYLIST_PATH, NULL);
@@ -314,6 +317,7 @@
omp_playlist_page_create()
{
GtkWidget *main_vbox, *scroll_box, *input_box, *button, *image, *alignment, *label;
+ gchar *image_file_name;
// Create main container
main_vbox = gtk_vbox_new(FALSE, 0);
@@ -341,7 +345,10 @@
input_box = gtk_hbox_new(FALSE, 0);
omp_playlist_page_entry = gtk_entry_new();
button = gtk_button_new();
- image = gtk_image_new_from_icon_name("gtk-add", GTK_ICON_SIZE_MENU);
+
+ image_file_name = g_build_filename(ui_image_path, "ico-playlist-new.png", NULL);
+ image = gtk_image_new_from_file(image_file_name);
+ g_free(image_file_name);
gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(omp_playlist_page_add_list), NULL);
More information about the commitlog
mailing list