r2669 - in trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2: . src

abraxa at sita.openmoko.org abraxa at sita.openmoko.org
Thu Aug 9 14:44:31 CEST 2007


Author: abraxa
Date: 2007-08-09 14:44:25 +0200 (Thu, 09 Aug 2007)
New Revision: 2669

Added:
   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/main_page.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.h
   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.h
Removed:
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h
Modified:
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/configure.ac
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/openmoko-mediaplayer.desktop
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am
   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/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/playback.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h
Log:
Reworked UI for seamless 2007.2 integration
Restructured code to better suit 2007.2 UI
Added automatic session handling
Added playlist UI foundation



Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO	2007-08-09 12:44:25 UTC (rev 2669)
@@ -2,9 +2,13 @@
 UI:
 	Add repeat mode indicator (different button pixmaps)
 	Make FFWD/REW buttons trigger repeatedly
+	Make Prev/Next buttons sensitive depending on playlist state
 	
 Backend:
 	Use GConf
+	Use GST_MESSAGE_DURATION and use saved value
+	Use GST_MESSAGE_TAG
+	Use GST_MESSAGE_BUFFERING
 	
 Issues:
 	How/where to store playlists? -> Single common path, omitting path chooser

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/configure.ac
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/configure.ac	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/configure.ac	2007-08-09 12:44:25 UTC (rev 2669)
@@ -37,8 +37,11 @@
 LIBS="-lspiff $LIBS"
 AC_CHECK_LIB(spiff, spiff_parse, [], [echo "Error: XSPF library (libspiff) not found"; exit -1])
 
+LIBS="-lmokoui2 $LIBS"
+AC_CHECK_LIB(mokoui2, moko_stock_register, [], [echo "Error: libmokoui2 not found"; exit -1])
 
 
+
 LIBS="$GTK_LIBS $OPENMOKO_LIBS $GSTREAMER_LIBS $LIBS"
 CFLAGS="$OPENMOKO_CFLAGS $GSTREAMER_CFLAGS $CFLAGS"
 

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/openmoko-mediaplayer.desktop
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/openmoko-mediaplayer.desktop	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/openmoko-mediaplayer.desktop	2007-08-09 12:44:25 UTC (rev 2669)
@@ -4,8 +4,9 @@
 Exec=openmoko-mediaplayer
 Icon=openmoko-mediaplayer
 MimeType=audio/x-scpls;audio/mp3;audio/x-mp3;audio/mpeg;audio/x-mpeg;audio/x-wav;application/x-ogg;
-Categories=Application;AudioVideo;Player;
+Categories=Application;AudioVideo;Player;Multimedia
 Terminal=false
 Type=Application
 Encoding=UTF-8
 SingleInstance=true
+StartupNotify=true

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am	2007-08-09 12:44:25 UTC (rev 2669)
@@ -24,8 +24,10 @@
 
 openmoko_mediaplayer_SOURCES = \
         main.c main.h \
-	mainwin.c mainwin.h \
 	playlist.c playlist.h \
 	playback.c playback.h \
 	guitools.c guitools.h \
-	persistent.c persistent.h
+	persistent.c persistent.h \
+	main_page.c main_page.h \
+	playlist_page.c playlist_page.h \
+	files_page.c files_page.h

Added: 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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -0,0 +1,28 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file files_page.c
+ * Playlist editor
+ */
+
+#include "files_page.h"
+

Added: 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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/files_page.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -0,0 +1,34 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file files_page.h
+ * Playlist editor
+ */
+
+#ifndef FILES_PAGE_H
+#define FILES_PAGE_H
+
+
+
+#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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -26,8 +26,12 @@
 
 #include "guitools.h"
 
+/// Absolute path to the UI pixmaps
+extern gchar *ui_image_path = NULL;
 
 
+
+
 /**
  * Loads an image from a file into a pixel buffer
  */
@@ -115,3 +119,24 @@
 	GtkWidget *image;
 	container_add_image_with_ref(container, image_name, &image);
 }
+
+
+/**
+ * Adds a child to a GtkNotebook, filling the page handle with a stock icon
+ */
+void
+omp_notebook_add_page_with_icon(GtkWidget *notebook, GtkWidget *child, const gchar *icon_name, int padding)
+{
+	GtkWidget *icon, *alignment;
+
+	icon = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+
+	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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/guitools.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -24,18 +24,22 @@
  * Various helper functions to aid with GUI creation and handling
  */
 
-#ifndef _GUITOOLS_H
-#define _GUITOOLS_H
+#ifndef GUITOOLS_H
+#define GUITOOLS_H
 
 #include <gtk/gtk.h>
 
-#define RELATIVE_UI_IMAGE_PATH "/images"
-gchar *ui_image_path;				///< Absolute path to the UI pixmaps
+#include "main.h"
 
+extern gchar *ui_image_path;
+
 GdkPixbuf *pixbuf_new_from_file(const gchar* file_name);
 GtkWidget *create_label(GtkWidget **label, gchar *font_info, gchar *color_desc, gfloat xalign, gfloat yalign, gfloat xscale, gfloat yscale, gint max_char_count);
 void container_add_image(GtkContainer *container, gchar *image_name);
 void container_add_image_with_ref(GtkContainer *container, gchar *image_name, GtkWidget **image);
 
+// These are for the main window's notebook used to switch UI pages
+void omp_notebook_add_page_with_icon(GtkWidget *notebook, GtkWidget *child, const gchar *icon_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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -44,20 +44,30 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "libmokoui2/moko-stock.h"
+
 #include "main.h"
-#include "mainwin.h"
+#include "main_page.h"
 #include "guitools.h"
 #include "playlist.h"
 #include "playback.h"
 #include "persistent.h"
 
-/// Determines how the segfault handler terminates the program
+// Determines how the segfault handler terminates the program
 //define HANDLE_SIGSEGV
 
-/// Enables GLib memory profiling when defined
+// Enables GLib memory profiling when defined
 //define DEBUG_MEM_PROFILE
 
+// The padding applied to the page handle's contents
+#define NOTEBOOK_PAGE_PADDING 6
 
+GtkWidget *omp_window = NULL;
+GtkWidget *omp_notebook = NULL;
+struct _omp_notebook_tabs *omp_notebook_tabs = NULL;
+
+
+
 /*
 void
 init_dbus()
@@ -83,13 +93,22 @@
 */
 
 /**
+ * Terminate the entire program normally
+ */
+void
+omp_application_terminate()
+{
+	gtk_main_quit();
+}
+
+/**
  * SIGSEGV signal handler
  */
 static void
 handler_sigsegfault(int value)
 {
 	g_printerr(_("Received SIGSEGV\n"
-		"This could be a bug in the OpenMoko Media Player.\n\n"));
+		"This might be a bug in the OpenMoko Media Player.\n\n"));
 
 #ifdef HANDLE_SIGSEGV
 	exit(EXIT_FAILURE);
@@ -99,14 +118,13 @@
 }
 
 /**
- * SIGUSR1 signal handler
- * @todo Should bring currently active window to front - which isn't necessarily the main window
+ * SIGUSR1 signal handler, restores already running application
  */
 static void
 handler_sigusr1(int value)
 {
 	// Bring main window to front
-	omp_main_window_show();
+	gtk_window_present(GTK_WINDOW(omp_window));
 
 	// Re-install handler
 	signal(SIGUSR1, handler_sigusr1);
@@ -200,6 +218,73 @@
 }
 
 /**
+ * Program termination event triggered by main window
+ */
+void
+omp_close(GtkWidget *widget, gpointer data)
+{
+	omp_application_terminate();
+}
+
+/**
+ * Creates the application's main window
+ */
+void
+omp_window_create()
+{
+	g_return_if_fail(omp_window == NULL);
+
+	// Create window
+	omp_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title(GTK_WINDOW(omp_window), _("Media Player"));
+	g_signal_connect(G_OBJECT(omp_window), "destroy", G_CALLBACK(omp_close), NULL);
+}
+
+/**
+ * Create the individual pages that make up the UI
+ * @note Must be called after the backends have been initialized so the signals exist that the UIs hook to
+ */
+void
+omp_window_create_pages()
+{
+	// Create and set up the notebook that contains the individual UI pages
+	omp_notebook = gtk_notebook_new();
+	g_object_set(G_OBJECT(omp_notebook), "can-focus", FALSE, "homogeneous", TRUE, NULL);
+	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(omp_notebook), GTK_POS_BOTTOM);
+	gtk_container_add(GTK_CONTAINER(omp_window), GTK_WIDGET(omp_notebook));
+
+	omp_notebook_tabs = g_new0(struct _omp_notebook_tabs, 1);
+
+	// Add main page
+	omp_notebook_tabs->main = omp_main_page_create(GTK_WINDOW(omp_window));
+	omp_notebook_add_page_with_icon(omp_notebook, omp_notebook_tabs->main,
+		MOKO_STOCK_SPEAKER, NOTEBOOK_PAGE_PADDING);
+
+	// Add playlist page
+	omp_notebook_tabs->playlists = omp_playlist_page_create(GTK_WINDOW(omp_window));
+	omp_notebook_add_page_with_icon(omp_notebook, omp_notebook_tabs->playlists,
+		MOKO_STOCK_VIEW, NOTEBOOK_PAGE_PADDING);
+}
+
+/**
+ * Frees all resources used by the main window
+ */
+void
+omp_window_free()
+{
+	g_free(omp_notebook_tabs);
+}
+
+/**
+ * Displays the main window and all widgets it contains
+ */
+void
+omp_window_show()
+{
+	gtk_widget_show_all(omp_window);
+}
+
+/**
  * If only I knew what this is
  */
 gint
@@ -228,7 +313,6 @@
 	}
 
 	gdk_threads_init();
-	gdk_threads_enter();
 
 	// Initialize miscellaneous things needed for the remote control interface
 	g_random_set_seed(time(NULL));
@@ -261,6 +345,7 @@
 	}
 
 	// Initialize various things necessary for the full player UI
+	moko_stock_register();
 	ui_image_path = g_build_filename(DATA_DIR, RELATIVE_UI_IMAGE_PATH, NULL);
 
 	g_set_application_name(_("Media Player"));
@@ -272,20 +357,20 @@
 
 	// Initialize playback, playlist and UI handling
 	omp_config_init();
-	omp_main_window_create();
+	omp_window_create();
 	omp_playback_init();
 	omp_playlist_init();
-	omp_main_connect_signals();
+	omp_window_create_pages();
 	omp_session_restore_state();
-	omp_main_window_show();
+	omp_window_show();
 
 	gtk_main();
-	gdk_threads_leave();
 
 	// Clean up
 	omp_playback_save_state();
 	omp_playback_free();
 	omp_playlist_free();
+	omp_window_free();
 	gst_deinit();
 	g_free(ui_image_path);
 

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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -24,8 +24,32 @@
  * Main file
  */
 
-#ifndef _MAIN_H
-#define _MAIN_H
+#ifndef MAIN_H
+#define MAIN_H
 
+#include <gtk/gtk.h>
 
+// This size is valid for the entire application and determines the size of the button's icons
+#define BUTTON_PIXMAP_SIZE 36
+
+// Where to find application-specific images relative to $DATA_DIR (/usr/share/openmoko-mediaplayer)?
+#define RELATIVE_UI_IMAGE_PATH "/images"
+
+// Where to find the playlist files relative to the user's home directory?
+#define RELATIVE_PLAYLIST_PATH "/playlists"
+
+// What file to save/load session data to/from? File name is relative to user's home directory
+#define SESSION_FILE_NAME "/.openmoko-mediaplayer"
+
+
+struct _omp_notebook_tabs
+{
+	GtkWidget *main, *playlists, *files;
+};
+
+extern struct _omp_notebook_tabs *omp_notebook_tabs;
+extern GtkWidget *omp_window;
+
+void omp_application_terminate();
+
 #endif

Added: 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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -0,0 +1,670 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file main_page.c
+ * Main UI handling
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <gtk/gtk.h>
+
+#include "main_page.h"
+#include "main.h"
+#include "guitools.h"
+#include "playlist.h"
+#include "playback.h"
+
+/// Contains all main window widgets that need to be changeable
+struct _main_widgets
+{
+	GtkWidget *title_label;
+	GtkWidget *artist_label;
+	GtkWidget *track_number_label;
+	GtkWidget *time_label;
+	GtkWidget *time_hscale;
+	GtkWidget *band_image[12];
+	GtkWidget *volume_image;
+	GtkWidget *volume_label;
+	GtkWidget *balance_image;
+	GtkWidget *play_pause_button_image;
+	GtkWidget *shuffle_button;
+	GtkWidget *repeat_button;
+	GtkWidget *playlist_button;
+} main_widgets;
+
+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
+
+
+
+/**
+ * Updates the UI volume display
+ * @param vol Volume to show, in percent
+ */
+void
+omp_change_vol_img(gint vol)
+{
+	// Sanity checks
+	if ( (vol < 0) || (vol > 100) )
+		g_printerr("Warning: volume passed to omp_change_vol_img() out of bounds\n");
+
+	if (vol < 0) vol = 0;
+	if (vol > 100) vol = 100;
+
+	gchar *image_file_name = g_strdup_printf("%s/ind-music-volume-%02d.png", ui_image_path, vol/10);
+	gtk_image_set_from_file(GTK_IMAGE(main_widgets.volume_image), image_file_name);
+
+	g_free(image_file_name);
+}
+
+/**
+ * Sets a desired EQ/visualization band to a new level
+ * @param pos Band to change (0..11)
+ * @param h Level to set (0..15, anything higher gets capped)
+ * @note The switch is supposed to make the levels pseudo-logarithmic?
+ */
+void
+omp_update_band(gint pos, gint level)
+{
+	// Sanity checks
+	g_return_if_fail( (pos < 0) && (pos > 11) );
+	g_return_if_fail(level > -1);
+
+	// Pseudo-logarithmize the value
+	gint value = 0;
+
+	switch (level)
+	{
+		case 0:
+		case 1:
+		case 2:
+			value = 1;
+			break;
+
+		case 3:
+		case 4:
+			value = 2;
+			break;
+
+		case 5:
+		case 6:
+			value = 3;
+			break;
+
+		case 7:
+		case 8:
+		case 9:
+		case 10:
+		case 11:
+		case 12:
+		case 13:
+		case 14:
+		case 15:
+			value = level-3;
+			break;
+
+		default:
+			value = 12;
+	}
+
+	// Determine file name of the new image to use and apply it
+	gchar *image_file_name = NULL;
+	image_file_name = g_strdup_printf("%s/ind-music-eq-%02d.png", ui_image_path, value);
+
+	gtk_image_set_from_file(GTK_IMAGE(main_widgets.band_image[pos]), image_file_name);
+
+	g_free(image_file_name);
+}
+
+/**
+ * Set artist label [Mockup arrow #1 - upper line]
+ */
+void
+omp_set_artist(const gchar *artist)
+{
+	if (!artist)
+	{
+		gtk_label_set_text(GTK_LABEL(main_widgets.artist_label), "Unknown Artist");
+		return;
+	}
+
+	gtk_label_set_text(GTK_LABEL(main_widgets.artist_label), artist);
+}
+
+/**
+ * Set title label [Mockup arrow #1 - lower line]
+ */
+void
+omp_set_title(const gchar *title)
+{
+	if (!title)
+	{
+		gtk_label_set_text(GTK_LABEL(main_widgets.title_label), "Unknown Title");
+		return;
+	}
+
+	gtk_label_set_text(GTK_LABEL(main_widgets.title_label), title);
+}
+
+/**
+ * Gets called when the time slider's value got changed (yes, that means it gets called at least once per second)
+ */
+void
+omp_main_time_slider_changed(GtkRange *range, gpointer data)
+{
+	if (omp_main_time_slider_was_dragged)
+	{
+		omp_main_time_slider_was_dragged = FALSE;
+
+		// Set new position and resume playback that was paused when dragging started
+		omp_playback_set_track_position(gtk_range_get_value(GTK_RANGE(range)));
+
+		// Update UI right away
+		gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
+	}
+}
+
+/**
+ * Gets called when the user starts dragging the time slider
+ */
+gboolean
+omp_main_time_slider_drag_start(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+	while (gtk_events_pending()) gtk_main_iteration();
+
+	// Prevent UI callbacks from messing with the slider position
+	omp_main_time_slider_can_update = FALSE;
+}
+
+/**
+ * Gets called when the user stops dragging the time slider
+ */
+gboolean
+omp_main_time_slider_drag_stop(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+	while (gtk_events_pending()) gtk_main_iteration();
+
+	// Allow UI callbacks to alter the the slider position again
+	omp_main_time_slider_can_update = TRUE;
+
+	// Notify the slider change callback that this time we indeed want to change position
+	omp_main_time_slider_was_dragged = TRUE;
+}
+
+/**
+ * Event handler for the Shuffle button
+ */
+void
+omp_shuffle_button_callback(GtkWidget *widget, gpointer data)
+{
+	// ...
+}
+
+/**
+ * Event handler for the Repeat button
+ */
+void
+omp_repeat_button_callback(GtkWidget *widget, gpointer data)
+{
+	// ...
+}
+
+/**
+ * Event handler for the Playlist button
+ */
+void
+omp_playlist_button_callback(GtkWidget *widget, gpointer data)
+{
+	// ...
+}
+
+/**
+ * Event handler for the Fast Forward button
+ */
+void
+omp_main_button_fast_forward_callback()
+{
+	// Set new position and resume playback that was paused when dragging started
+	omp_playback_set_track_position(omp_playback_get_track_position()+BUTTON_SEEK_DISTANCE);
+
+	// Update UI right away
+	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
+}
+
+/**
+ * Event handler for the Rewind button
+ */
+void
+omp_main_button_rewind_callback()
+{
+	// Set new position and resume playback that was paused when dragging started
+	omp_playback_set_track_position(omp_playback_get_track_position()-BUTTON_SEEK_DISTANCE);
+
+	// Update UI right away
+	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
+}
+
+/**
+ * Event handler for the Play/Pause button
+ */
+void
+omp_main_button_play_pause_callback()
+{
+	if (omp_playback_get_state() != OMP_PLAYBACK_STATE_PLAYING)
+	{
+		omp_playback_play();
+
+	} else {
+
+		omp_playback_pause();
+	}
+}
+
+/**
+ * Creates a button framed by a GtkAlignment
+ * @param image_name Path and file name of the image to use as pixmap
+ * @return A GtkAlignment containing the button
+ */
+GtkWidget*
+omp_button_create(gchar *image_name, gint pad_left, GCallback callback, GtkWidget **button)
+{
+	GtkWidget *image;
+	gchar *image_file_name;
+
+	GtkWidget *alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, pad_left, 0);
+
+	*button = gtk_toggle_button_new();
+	gtk_widget_set_size_request(GTK_WIDGET(*button), 66, 66);
+	g_signal_connect(G_OBJECT(*button), "clicked", G_CALLBACK(callback), NULL);
+	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(*button), GTK_CAN_FOCUS);
+	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(*button));
+
+	g_object_set(G_OBJECT(*button), "xalign", (gfloat)0.37, "yalign", (gfloat)0.37, NULL);
+
+	image_file_name = g_build_path("/", ui_image_path, image_name, NULL);
+	image = gtk_image_new_from_file(image_file_name);
+	g_free(image_file_name);
+	gtk_container_add(GTK_CONTAINER(*button), GTK_WIDGET(image));
+
+	return alignment;
+}
+
+/**
+ * Creates a button with a stock pixmap and returns it
+ * @param image_name The name of the image resource to use, not a file name
+ * @return The button
+ */
+GtkWidget*
+omp_stock_button_create(gchar *image_name, GtkWidget **image, GCallback callback)
+{
+	GtkWidget *button;
+
+	button = gtk_button_new();
+	gtk_widget_set_size_request(GTK_WIDGET(button), 66, 66);
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), NULL);
+	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_FOCUS);
+
+	g_object_set(G_OBJECT(button), "xalign", (gfloat)0.37, "yalign", (gfloat)0.37, NULL);
+
+	*image = gtk_image_new_from_icon_name(image_name, BUTTON_PIXMAP_SIZE);
+	gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(*image));
+
+	return button;
+}
+
+/**
+ * Creates the main UI
+ */
+void
+omp_main_widgets_create(GtkContainer *destination)
+{
+	GtkWidget *alignment;
+	GtkWidget *mainvbox;
+	GtkWidget *background_vbox;
+	GtkWidget *upper_hbox, *middle_hbox, *lower_hbox, *controls_hbox;
+	GtkWidget *middle_right_vbox;
+	GtkWidget *image, *button;
+
+	gchar *image_file_name, *caption;
+	gint i;
+
+	// Add mainvbox to destination container
+	mainvbox = gtk_vbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(destination), GTK_WIDGET(mainvbox));
+
+	// Title label
+	alignment = create_label(&main_widgets.title_label, "Bitstream Vera Sans 24", "black", 0, 0, 1, 0, 18);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 18, 0, 50, 30);
+	gtk_label_set_text(GTK_LABEL(main_widgets.title_label), "No track available");
+	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+
+	// Artist label
+	alignment = create_label(&main_widgets.artist_label, "Bitstream Vera Sans 14", "black", 0, 0, 1, 0, 30);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 0, 50, 30);
+	gtk_label_set_text(GTK_LABEL(main_widgets.artist_label), "");
+	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+
+	// --- --- --- --- --- Upper hbox --- --- --- --- ---
+
+	// Add upper_hbox to mainvbox for track number and time display
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 20, 0, 50, 30);
+	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+	upper_hbox = gtk_hbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(upper_hbox));
+
+	// Track number icon
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 2, 0, 0, 15);
+	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+	container_add_image(GTK_CONTAINER(alignment), "ico-track.png");
+
+	// Track number
+	alignment = create_label(&main_widgets.track_number_label, "Bitstream Vera Sans 14", "black", 0, 0, 0, 0, 12);
+	caption = g_strdup_printf(WIDGET_CAPTION_TRACK_NUM, 0, 0);
+	gtk_label_set_text(GTK_LABEL(main_widgets.track_number_label), caption);
+	g_free(caption);
+	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+
+	// Time icon
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 2, 0, 48, 15);
+	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+	container_add_image(GTK_CONTAINER(alignment), "ico-time.png");
+
+	// Time
+	alignment = create_label(&main_widgets.time_label, "Bitstream Vera Sans 14", "black", 0, 0, 0, 0, 12);
+	caption = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME, 0, 0, 0, 0);
+	gtk_label_set_text(GTK_LABEL(main_widgets.time_label), caption);
+	g_free(caption);
+	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+
+	// --- --- --- --- --- Slider --- --- --- --- ---
+
+	// Time hscale
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 0, 48, 0);
+	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+
+	main_widgets.time_hscale = gtk_hscale_new_with_range(0.0, 338.0, 1.0);
+	gtk_scale_set_draw_value(GTK_SCALE(main_widgets.time_hscale), FALSE);
+	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(main_widgets.time_hscale), GTK_CAN_FOCUS);
+	gtk_widget_set_size_request(GTK_WIDGET(main_widgets.time_hscale), 338, 35);
+	gtk_range_set_update_policy(GTK_RANGE(main_widgets.time_hscale), GTK_UPDATE_DISCONTINUOUS);
+	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), 0.0);
+	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "value_changed",					G_CALLBACK(omp_main_time_slider_changed), NULL);
+	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "button-press-event",		G_CALLBACK(omp_main_time_slider_drag_start), NULL);
+	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "button-release-event",	G_CALLBACK(omp_main_time_slider_drag_stop), NULL);
+	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(main_widgets.time_hscale));
+
+	// --- --- --- --- --- Middle hbox --- --- --- --- ---
+
+	// Add middle_hbox to mainvbox for the EQ/volume/balance widgets
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 41, 0, 70, 0);
+	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+
+	middle_hbox = gtk_hbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(middle_hbox));
+
+	// EQ/Visualization bands
+	image_file_name = g_build_path("/", ui_image_path, "ind-music-eq-12.png", NULL);
+
+	for (i=0; i<12; i++)
+	{
+		alignment = gtk_alignment_new(0, 0, 0, 0);
+		gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 0, 0);
+		gtk_box_pack_start(GTK_BOX(middle_hbox), alignment, TRUE, TRUE, 0);
+		main_widgets.band_image[i] = gtk_image_new_from_file(image_file_name);
+		gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(main_widgets.band_image[i]));
+	}
+
+	g_free(image_file_name);
+
+	// Add vbox containing volume and balance controls
+	middle_right_vbox = gtk_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(middle_hbox), GTK_WIDGET(middle_right_vbox), TRUE, TRUE, 0);
+
+	// Volume hbox
+	GtkWidget* volume_box = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(middle_right_vbox), volume_box, TRUE, TRUE, 0);
+
+	// Volume image
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 4, 0, 25, 0);
+	gtk_box_pack_start(GTK_BOX(volume_box), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+	container_add_image_with_ref(GTK_CONTAINER(alignment), "ind-music-volume-00.png", &main_widgets.volume_image);
+
+	// Volume label
+	alignment = create_label(&main_widgets.volume_label, "Sans 14", "darkorange", 0, 0, 1, 0, 4);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 6, 0, 10, 0);
+	gtk_box_pack_start(GTK_BOX(volume_box), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+	caption = g_strdup_printf(WIDGET_CAPTION_VOLUME, 0);
+	gtk_label_set_text(GTK_LABEL(main_widgets.volume_label), caption);
+	g_free(caption);
+
+	//  Balance image
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 10, 0, 35, 0);
+	gtk_box_pack_start(GTK_BOX(middle_right_vbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
+	container_add_image_with_ref(GTK_CONTAINER(alignment), "ind-music-pan-0.png", &main_widgets.balance_image);
+
+	// --- --- --- --- --- Lower hbox --- --- --- --- ---
+
+	// Add lower hbox containing the three rectangular buttons
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 25, 0, 0, 0);
+	gtk_box_pack_start(GTK_BOX(mainvbox), alignment, TRUE, TRUE, 0);
+	lower_hbox = gtk_hbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(alignment), lower_hbox);
+
+	// Shuffle toggle button
+	alignment = omp_button_create("ico-shuffle.png", 108, G_CALLBACK(omp_shuffle_button_callback), &main_widgets.shuffle_button);
+	gtk_box_pack_start(GTK_BOX(lower_hbox), alignment, TRUE, TRUE, 0);
+
+	// Repeat toggle button
+	alignment = omp_button_create("ico-repeat.png", 10, G_CALLBACK(omp_repeat_button_callback), &main_widgets.repeat_button);
+	gtk_box_pack_start(GTK_BOX(lower_hbox), alignment, TRUE, TRUE, 0);
+
+	// Playlist button
+	alignment = omp_button_create("ico-list.png", 10, G_CALLBACK(omp_playlist_button_callback), &main_widgets.playlist_button);
+	gtk_box_pack_start(GTK_BOX(lower_hbox), alignment, TRUE, TRUE, 0);
+
+	// --- --- --- --- --- Player controls --- --- --- --- --- ---
+
+	alignment = gtk_alignment_new(0, 0, 1, 0);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 40, 0, 0, 0);
+	gtk_box_pack_start(GTK_BOX(mainvbox), alignment, TRUE, TRUE, 0);
+
+	controls_hbox = gtk_hbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(alignment), controls_hbox);
+
+	gtk_box_set_homogeneous(GTK_BOX(controls_hbox), TRUE);
+
+	// Previous Track button
+	button = omp_stock_button_create("gtk-media-previous-ltr", &image, G_CALLBACK(omp_playlist_set_prev_track));
+	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
+	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
+
+	// Rewind button
+	button = omp_stock_button_create("gtk-media-rewind-ltr", &image, G_CALLBACK(omp_main_button_rewind_callback));
+	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
+	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
+
+	// Play/Pause button
+	button = omp_stock_button_create("gtk-media-play-ltr", &main_widgets.play_pause_button_image, G_CALLBACK(omp_main_button_play_pause_callback));
+	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
+	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
+
+	// Fast Forward button
+	button = omp_stock_button_create("gtk-media-forward-ltr", &image, G_CALLBACK(omp_main_button_fast_forward_callback));
+	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
+	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
+
+	// Next Track button
+	button = omp_stock_button_create("gtk-media-next-ltr", &image, G_CALLBACK(omp_playlist_set_next_track));
+	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
+	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
+}
+
+/**
+ * Create the main UI page and all its elements
+ */
+GtkWidget *
+omp_main_page_create(GtkWindow *window)
+{
+	GtkWidget *alignment, *bg_muxer;
+
+	bg_muxer = gtk_fixed_new();
+
+	// Background image
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	container_add_image(GTK_CONTAINER(alignment), "background.png");
+	gtk_fixed_put(GTK_FIXED(bg_muxer), GTK_WIDGET(alignment), 15, 30);
+	
+	// Create all widgets
+	alignment = gtk_alignment_new(0, 0, 0, 0);
+	omp_main_widgets_create(GTK_CONTAINER(alignment));
+	gtk_fixed_put(GTK_FIXED(bg_muxer), GTK_WIDGET(alignment), 20, 47);
+
+	// Set up signal handlers
+	g_signal_connect(G_OBJECT(window), OMP_EVENT_PLAYLIST_TRACK_CHANGED,		G_CALLBACK(omp_main_update_track_change), NULL);
+	g_signal_connect(G_OBJECT(window), OMP_EVENT_PLAYBACK_STATUS_CHANGED,		G_CALLBACK(omp_main_update_status_change), NULL);
+	g_signal_connect(G_OBJECT(window), OMP_EVENT_PLAYBACK_POSITION_CHANGED,	G_CALLBACK(omp_main_update_track_position), NULL);
+
+	return bg_muxer;
+}
+
+/**
+ * Evaluates current track information and updates the config/UI if necessary
+ * @note This function only checks elements that don't change too often - for the rest we have specialized functions below
+ */
+void
+omp_main_update_track_change()
+{
+	static gint old_track_count = 0;
+	static gint old_track_id = 0;
+	static gulong old_track_length = 0;
+
+	gulong track_length, track_position;
+	gchar *text;
+
+	// Track id/track count changed?
+	if ( (omp_playlist_track_count != old_track_count) || (omp_playlist_current_track_id != old_track_id) )
+	{
+		old_track_count = omp_playlist_track_count;
+		old_track_id = omp_playlist_current_track_id;
+
+		// Update session
+		omp_session_set_track_id(omp_playlist_current_track_id);
+
+		// Update label
+		text = g_strdup_printf(WIDGET_CAPTION_TRACK_NUM, omp_playlist_current_track_id+1, omp_playlist_track_count);
+		gtk_label_set_text(GTK_LABEL(main_widgets.track_number_label), text);
+		g_free(text);
+	}
+
+	// Got a track length change?
+	track_length = omp_playback_get_track_length();
+
+	if (track_length != old_track_length)
+	{
+		old_track_length = track_length;
+		track_position = omp_playback_get_track_position();
+
+		// Set new time slider increments: one tap is 10% of the track's playing time
+		gtk_range_set_increments(GTK_RANGE(main_widgets.time_hscale), track_length/10, track_length/10);
+
+		// Update label and slider
+		text = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME,
+			track_position / 60, track_position % 60,
+			track_length / 60, track_length % 60);
+		gtk_label_set_text(GTK_LABEL(main_widgets.time_label), text);
+		g_free(text);
+
+		if (omp_main_time_slider_can_update)
+		{
+			// We don't want to set both min/max to 0 as this triggers a critial GTK warning, so we set 0/1 instead in that case
+			gtk_range_set_range(GTK_RANGE(main_widgets.time_hscale), 0, track_length ? track_length : 1);
+			gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), track_position);
+		}
+	}
+}
+
+/**
+ * Updates the UI if playback engine switched between paused and playing modes
+ */
+void
+omp_main_update_status_change()
+{
+	// Update Play/Pause button pixmap
+	if (omp_playback_get_state() == OMP_PLAYBACK_STATE_PAUSED)
+	{
+		gtk_image_set_from_icon_name(GTK_IMAGE(main_widgets.play_pause_button_image), "gtk-media-play-ltr", BUTTON_PIXMAP_SIZE);
+	} else {
+		gtk_image_set_from_icon_name(GTK_IMAGE(main_widgets.play_pause_button_image), "gtk-media-pause", BUTTON_PIXMAP_SIZE);
+	}
+}
+
+/**
+ * Updates the UI if the playback position changed
+ */
+void
+omp_main_update_track_position()
+{
+	static gulong old_track_position = 0;
+
+	gulong track_position, track_length;
+	gchar *text;
+
+	// Got a track length change?
+	track_position = omp_playback_get_track_position();
+	{
+		old_track_position = track_position;
+		track_length = omp_playback_get_track_length();
+
+		// Update UI
+		text = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME,
+			track_position / 60, track_position % 60,
+			track_length / 60, track_length % 60);
+		gtk_label_set_text(GTK_LABEL(main_widgets.time_label), text);
+		g_free(text);
+
+		if (omp_main_time_slider_can_update)
+		{
+			// We don't want to set both min/max to 0 as this triggers a critial GTK warning, so we set 0/1 instead in that case
+			gtk_range_set_range(GTK_RANGE(main_widgets.time_hscale), 0, track_length ? track_length : 1);
+			gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), track_position);
+		}
+	}
+
+}
+

Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.h	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main_page.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -0,0 +1,46 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file main_page.h
+ * Main UI handling
+ */
+
+#ifndef MAIN_PAGE_H
+#define MAIN_PAGE_H
+
+#include <gtk/gtk.h>
+
+#define WIDGET_CAPTION_TRACK_TIME "%d:%.2d / %d:%.2d"
+#define WIDGET_CAPTION_TRACK_NUM "%.3d / %.3d"
+#define WIDGET_CAPTION_VOLUME "%d%%"
+
+// Determines how many seconds the engine will seek if the FFWD/REW buttons are clicked
+#define BUTTON_SEEK_DISTANCE 10
+
+
+GtkWidget *omp_main_page_create(GtkWindow *window);
+
+void omp_main_update_track_change();
+void omp_main_update_status_change();
+void omp_main_update_track_position();
+
+#endif

Deleted: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -1,743 +0,0 @@
-/*
- *  OpenMoko Media Player
- *   http://openmoko.org/
- *
- *  Copyright (C) 2007 by the OpenMoko team
- *
- *  This program 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 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program 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, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/**
- * @file mainwin.c
- * Main window handling
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include <gtk/gtk.h>
-
-#include "mainwin.h"
-#include "main.h"
-#include "guitools.h"
-#include "playlist.h"
-#include "playback.h"
-
-#define OMP_BUTTON_PIXMAP_SIZE 36
-
-/// Contains all main window widgets that need to be changeable
-struct _main_widgets
-{
-	GtkWidget *title_label;
-	GtkWidget *artist_label;
-	GtkWidget *track_number_label;
-	GtkWidget *time_label;
-	GtkWidget *time_hscale;
-	GtkWidget *band_image[12];
-	GtkWidget *volume_image;
-	GtkWidget *volume_label;
-	GtkWidget *balance_image;
-	GtkWidget *play_pause_button_image;
-	GtkWidget *shuffle_button;
-	GtkWidget *repeat_button;
-	GtkWidget *playlist_button;
-} main_widgets;
-
-GtkWidget *omp_main_window = NULL;
-
-gboolean omp_main_time_slider_can_update = TRUE;
-gboolean omp_main_time_slider_was_dragged = FALSE;
-
-
-/**
- * Terminate the entire program
- */
-void
-omp_application_terminate()
-{
-	// Tell GTK to leave the message loop
-	gtk_main_quit();
-}
-
-/**
- * Program termination event triggered by main window
- */
-void
-omp_main_quit(GtkWidget* widget, gpointer data)
-{
-	omp_application_terminate();
-}
-
-/**
- * Updates the UI volume display
- * @param vol Volume to show, in percent
- */
-void
-omp_change_vol_img(gint vol)
-{
-	// Sanity checks
-	if ( (vol < 0) || (vol > 100) )
-		g_printerr("Warning: volume passed to omp_change_vol_img() out of bounds\n");
-
-	if (vol < 0) vol = 0;
-	if (vol > 100) vol = 100;
-
-	gchar *image_file_name = g_strdup_printf("%s/ind-music-volume-%02d.png", ui_image_path, vol/10);
-	gtk_image_set_from_file(GTK_IMAGE(main_widgets.volume_image), image_file_name);
-
-	g_free(image_file_name);
-}
-
-/**
- * Sets a desired EQ/visualization band to a new level
- * @param pos Band to change (0..11)
- * @param h Level to set (0..15, anything higher gets capped)
- * @note The switch is supposed to make the levels pseudo-logarithmic?
- */
-void
-omp_update_band(gint pos, gint level)
-{
-	// Sanity checks
-	g_return_if_fail( (pos < 0) && (pos > 11) );
-	g_return_if_fail(level > -1);
-
-	// Pseudo-logarithmize the value
-	gint value = 0;
-
-	switch (level)
-	{
-		case 0:
-		case 1:
-		case 2:
-			value = 1;
-			break;
-
-		case 3:
-		case 4:
-			value = 2;
-			break;
-
-		case 5:
-		case 6:
-			value = 3;
-			break;
-
-		case 7:
-		case 8:
-		case 9:
-		case 10:
-		case 11:
-		case 12:
-		case 13:
-		case 14:
-		case 15:
-			value = level-3;
-			break;
-
-		default:
-			value = 12;
-	}
-
-	// Determine file name of the new image to use and apply it
-	gchar *image_file_name = NULL;
-	image_file_name = g_strdup_printf("%s/ind-music-eq-%02d.png", ui_image_path, value);
-
-	gtk_image_set_from_file(GTK_IMAGE(main_widgets.band_image[pos]), image_file_name);
-//	gtk_widget_show(GTK_IMAGE(main_widgets.band_image[pos]));
-
-	g_free(image_file_name);
-}
-
-/**
- * Set artist label [Mockup arrow #1 - upper line]
- */
-void
-omp_set_artist(const gchar* artist)
-{
-	if (!artist)
-	{
-		gtk_label_set_text(GTK_LABEL(main_widgets.artist_label), "Unknown Artist");
-		return;
-	}
-
-	gtk_label_set_text(GTK_LABEL(main_widgets.artist_label), artist);
-}
-
-/**
- * Set title label [Mockup arrow #1 - lower line]
- */
-void
-omp_set_title(const gchar *title)
-{
-	if (!title)
-	{
-		gtk_label_set_text(GTK_LABEL(main_widgets.title_label), "Unknown Title");
-		return;
-	}
-
-	gtk_label_set_text(GTK_LABEL(main_widgets.title_label), title);
-}
-
-/**
- * Gets called when the time slider's value got changed (yes, that means it gets called every second, too)
- */
-void
-omp_main_time_slider_changed(GtkRange *range, gpointer data)
-{
-	if (omp_main_time_slider_was_dragged)
-	{
-		omp_main_time_slider_was_dragged = FALSE;
-
-		// Set new position and resume playback that was paused when dragging started
-		omp_playback_set_track_position(gtk_range_get_value(GTK_RANGE(range)));
-
-		// Update UI right away
-		gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
-	}
-}
-
-/**
- * Gets called when the user starts dragging the time slider
- */
-gboolean
-omp_main_time_slider_drag_start(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
-{
-	while (gtk_events_pending()) gtk_main_iteration();
-
-	// Prevent UI callbacks from messing with the slider position
-	omp_main_time_slider_can_update = FALSE;
-}
-
-/**
- * Gets called when the user stops dragging the time slider
- */
-gboolean
-omp_main_time_slider_drag_stop(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
-{
-	while (gtk_events_pending()) gtk_main_iteration();
-
-	// Allow UI callbacks to alter the the slider position again
-	omp_main_time_slider_can_update = TRUE;
-
-	// Notify the slider change callback that this time we indeed want to change position
-	omp_main_time_slider_was_dragged = TRUE;
-}
-
-void
-omp_shuffle_button_callback(GtkWidget* widget, gpointer data)
-{
-/*    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
-    {
-	cfg.shuffle = TRUE;	    
-//	playlist_set_shuffle(TRUE);
-    }
-    else
-    {
-	cfg.shuffle= FALSE;
-//	playlist_set_shuffle(FALSE);
-    } */
-}
-
-void
-omp_repeat_button_callback(GtkWidget* widget, gpointer data)
-{
-    /*if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
-    {
-	cfg.repeat = TRUE;
-    }
-    else
-    {
-	cfg.repeat = FALSE;
-    }*/
-}
-
-void
-omp_playlist_button_callback(GtkWidget *sender, gpointer data)
-{
-	// ...
-}
-
-/**
- * Event handler for the Fast Forward button
- */
-void
-omp_main_button_fast_forward_callback()
-{
-	// Set new position and resume playback that was paused when dragging started
-	omp_playback_set_track_position(omp_playback_get_track_position()+BUTTON_SEEK_DISTANCE);
-
-	// Update UI right away
-	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
-}
-
-/**
- * Event handler for the Rewind button
- */
-void
-omp_main_button_rewind_callback()
-{
-	// Set new position and resume playback that was paused when dragging started
-	omp_playback_set_track_position(omp_playback_get_track_position()-BUTTON_SEEK_DISTANCE);
-
-	// Update UI right away
-	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
-}
-
-/**
- * Event handler for the Play/Pause button
- * @todo Pixmap change
- */
-void
-omp_main_button_play_pause_callback()
-{
-	if (omp_playback_get_state() != OMP_PLAYBACK_STATE_PLAYING)
-	{
-		omp_playback_play();
-
-	} else {
-
-		omp_playback_pause();
-	}
-}
-
-/**
- * Creates a toggle button framed by a GtkAlignment
- * @param image_name Path and file name of the image to use as pixmap
- * @return A GtkAlignment containing the button
- */
-GtkWidget*
-omp_toggle_button_create(gchar *image_name, gint pad_left, GCallback callback, GtkWidget **button)
-{
-	GtkWidget *image;
-	gchar *image_file_name;
-
-	GtkWidget *alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, pad_left, 0);
-
-	*button = gtk_toggle_button_new();
-	gtk_widget_set_size_request(GTK_WIDGET(*button), 66, 66);
-	g_signal_connect(G_OBJECT(*button), "clicked", G_CALLBACK(callback), NULL);
-	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(*button), GTK_CAN_FOCUS);
-	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(*button));
-
-	g_object_set(G_OBJECT(*button), "xalign", (gfloat)0.37, "yalign", (gfloat)0.37, NULL);
-
-	image_file_name = g_build_path("/", ui_image_path, image_name, NULL);
-	image = gtk_image_new_from_file(image_file_name);
-	g_free(image_file_name);
-	gtk_container_add(GTK_CONTAINER(*button), GTK_WIDGET(image));
-
-	return alignment;
-}
-
-/**
- * Creates a button with a stock pixmap and returns it
- * @param image_name The name of the image resource to use, not a file name
- * @return The button
- */
-GtkWidget*
-omp_stock_button_create(gchar *image_name, GtkWidget **image, GCallback callback)
-{
-	GtkWidget *button;
-
-	button = gtk_button_new();
-	gtk_widget_set_size_request(GTK_WIDGET(button), 66, 66);
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), NULL);
-	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_FOCUS);
-
-	g_object_set(G_OBJECT(button), "xalign", (gfloat)0.37, "yalign", (gfloat)0.37, NULL);
-
-	*image = gtk_image_new_from_icon_name(image_name, OMP_BUTTON_PIXMAP_SIZE);
-	gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(*image));
-
-	return button;
-}
-
-/**
- * Show the main window, create it first if necessary
- */
-void
-omp_main_window_show()
-{
-	if (!omp_main_window)
-	{
-		omp_main_window_create();
-	}
-
-	gtk_widget_show(GTK_WIDGET(omp_main_window));
-}
-
-/**
- * Hide the main window
- */
-void
-omp_main_window_hide()
-{
-	gtk_widget_hide(GTK_WIDGET(omp_main_window));
-}
-
-/**
- * Creates the main window's UI
- */
-void
-omp_main_widgets_create(GtkContainer *destination)
-{
-	GtkWidget *alignment;
-	GtkWidget *mainvbox;
-	GtkWidget *background_vbox;
-	GtkWidget *upper_hbox, *middle_hbox, *lower_hbox, *controls_hbox;
-	GtkWidget *middle_right_vbox;
-	GtkWidget *image, *button;
-
-	gchar *image_file_name, *caption;
-	gint i;
-
-	// Add mainvbox to destination container
-	mainvbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(destination), GTK_WIDGET(mainvbox));
-
-	// Title label
-	alignment = create_label(&main_widgets.title_label, "Bitstream Vera Sans 24", "black", 0, 0, 1, 0, 18);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 18, 0, 50, 30);
-	gtk_label_set_text(GTK_LABEL(main_widgets.title_label), "No track available");
-	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-
-	// Artist label
-	alignment = create_label(&main_widgets.artist_label, "Bitstream Vera Sans 14", "black", 0, 0, 1, 0, 30);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 0, 50, 30);
-	gtk_label_set_text(GTK_LABEL(main_widgets.artist_label), "");
-	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-
-	// --- --- --- --- --- Upper hbox --- --- --- --- ---
-
-	// Add upper_hbox to mainvbox for track number and time display
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 20, 0, 50, 30);
-	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-	upper_hbox = gtk_hbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(upper_hbox));
-
-	// Track number icon
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 2, 0, 0, 15);
-	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-	container_add_image(GTK_CONTAINER(alignment), "ico-track.png");
-
-	// Track number
-	alignment = create_label(&main_widgets.track_number_label, "Bitstream Vera Sans 14", "black", 0, 0, 0, 0, 12);
-	caption = g_strdup_printf(WIDGET_CAPTION_TRACK_NUM, 0, 0);
-	gtk_label_set_text(GTK_LABEL(main_widgets.track_number_label), caption);
-	g_free(caption);
-	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-
-	// Time icon
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 2, 0, 48, 15);
-	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-	container_add_image(GTK_CONTAINER(alignment), "ico-time.png");
-
-	// Time
-	alignment = create_label(&main_widgets.time_label, "Bitstream Vera Sans 14", "black", 0, 0, 0, 0, 12);
-	caption = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME, 0, 0, 0, 0);
-	gtk_label_set_text(GTK_LABEL(main_widgets.time_label), caption);
-	g_free(caption);
-	gtk_box_pack_start(GTK_BOX(upper_hbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-
-	// --- --- --- --- --- Slider --- --- --- --- ---
-
-	// Time hscale
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 0, 48, 0);
-	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-
-	main_widgets.time_hscale = gtk_hscale_new_with_range(0.0, 338.0, 1.0);
-	gtk_scale_set_draw_value(GTK_SCALE(main_widgets.time_hscale), FALSE);
-	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(main_widgets.time_hscale), GTK_CAN_FOCUS);
-	gtk_widget_set_size_request(GTK_WIDGET(main_widgets.time_hscale), 338, 35);
-	gtk_range_set_update_policy(GTK_RANGE(main_widgets.time_hscale), GTK_UPDATE_DISCONTINUOUS);
-	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), 0.0);
-	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "value_changed",					G_CALLBACK(omp_main_time_slider_changed), NULL);
-	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "button-press-event",		G_CALLBACK(omp_main_time_slider_drag_start), NULL);
-	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "button-release-event",	G_CALLBACK(omp_main_time_slider_drag_stop), NULL);
-	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(main_widgets.time_hscale));
-
-	// --- --- --- --- --- Middle hbox --- --- --- --- ---
-
-	// Add middle_hbox to mainvbox for the EQ/volume/balance widgets
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 41, 0, 70, 0);
-	gtk_box_pack_start(GTK_BOX(mainvbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-
-	middle_hbox = gtk_hbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(middle_hbox));
-
-	// EQ/Visualization bands
-	image_file_name = g_build_path("/", ui_image_path, "ind-music-eq-12.png", NULL);
-
-	for (i=0; i<12; i++)
-	{
-		alignment = gtk_alignment_new(0, 0, 0, 0);
-		gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 0, 0);
-		gtk_box_pack_start(GTK_BOX(middle_hbox), alignment, TRUE, TRUE, 0);
-		main_widgets.band_image[i] = gtk_image_new_from_file(image_file_name);
-		gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(main_widgets.band_image[i]));
-	}
-
-	g_free(image_file_name);
-
-	// Add vbox containing volume and balance controls
-	middle_right_vbox = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(middle_hbox), GTK_WIDGET(middle_right_vbox), TRUE, TRUE, 0);
-
-	// Volume hbox
-	GtkWidget* volume_box = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(middle_right_vbox), volume_box, TRUE, TRUE, 0);
-
-	// Volume image
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 4, 0, 25, 0);
-	gtk_box_pack_start(GTK_BOX(volume_box), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-	container_add_image_with_ref(GTK_CONTAINER(alignment), "ind-music-volume-00.png", &main_widgets.volume_image);
-
-	// Volume label
-	alignment = create_label(&main_widgets.volume_label, "Sans 14", "darkorange", 0, 0, 1, 0, 4);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 6, 0, 10, 0);
-	gtk_box_pack_start(GTK_BOX(volume_box), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-	caption = g_strdup_printf(WIDGET_CAPTION_VOLUME, 0);
-	gtk_label_set_text(GTK_LABEL(main_widgets.volume_label), caption);
-	g_free(caption);
-
-	//  Balance image
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 10, 0, 35, 0);
-	gtk_box_pack_start(GTK_BOX(middle_right_vbox), GTK_WIDGET(alignment), TRUE, TRUE, 0);
-	container_add_image_with_ref(GTK_CONTAINER(alignment), "ind-music-pan-0.png", &main_widgets.balance_image);
-
-	// --- --- --- --- --- Lower hbox --- --- --- --- ---
-
-	// Add lower hbox containing the three rectangular buttons
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 25, 0, 0, 0);
-	gtk_box_pack_start(GTK_BOX(mainvbox), alignment, TRUE, TRUE, 0);
-	lower_hbox = gtk_hbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(alignment), lower_hbox);
-
-	// Shuffle toggle button
-	alignment = omp_toggle_button_create("ico-shuffle.png", 108, G_CALLBACK(omp_shuffle_button_callback), &main_widgets.shuffle_button);
-	gtk_box_pack_start(GTK_BOX(lower_hbox), alignment, TRUE, TRUE, 0);
-
-	// Repeat toggle button
-	alignment = omp_toggle_button_create("ico-repeat.png", 10, G_CALLBACK(omp_repeat_button_callback), &main_widgets.repeat_button);
-	gtk_box_pack_start(GTK_BOX(lower_hbox), alignment, TRUE, TRUE, 0);
-
-	// Playlist button
-	alignment = omp_toggle_button_create("ico-list.png", 10, G_CALLBACK(omp_playlist_button_callback), &main_widgets.playlist_button);
-	gtk_box_pack_start(GTK_BOX(lower_hbox), alignment, TRUE, TRUE, 0);
-
-	// --- --- --- --- --- Player controls --- --- --- --- --- ---
-
-	alignment = gtk_alignment_new(0, 0, 1, 0);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 40, 0, 0, 0);
-	gtk_box_pack_start(GTK_BOX(mainvbox), alignment, TRUE, TRUE, 0);
-
-	controls_hbox = gtk_hbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(alignment), controls_hbox);
-
-	gtk_box_set_homogeneous(GTK_BOX(controls_hbox), TRUE);
-
-	// Previous Track button
-	button = omp_stock_button_create("gtk-media-previous-ltr", &image, G_CALLBACK(omp_playlist_set_prev_track));
-	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
-	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
-
-	// Rewind button
-	button = omp_stock_button_create("gtk-media-rewind-ltr", &image, G_CALLBACK(omp_main_button_rewind_callback));
-	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
-	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
-
-	// Play/Pause button
-	button = omp_stock_button_create("gtk-media-play-ltr", &main_widgets.play_pause_button_image, G_CALLBACK(omp_main_button_play_pause_callback));
-	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
-	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
-
-	// Fast Forward button
-	button = omp_stock_button_create("gtk-media-forward-ltr", &image, G_CALLBACK(omp_main_button_fast_forward_callback));
-	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
-	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
-
-	// Next Track button
-	button = omp_stock_button_create("gtk-media-next-ltr", &image, G_CALLBACK(omp_playlist_set_next_track));
-	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
-	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
-}
-
-/**
- * Create the main window and all its UI elements
- * @todo Make all widget positions and aligments relative
- */
-void
-omp_main_window_create()
-{
-	GtkWidget *alignment, *bg_muxer;
-
-	// Sanity check
-	g_assert(omp_main_window == NULL);
-
-	bg_muxer = gtk_fixed_new();
-
-	// Create the main window
-	omp_main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_title(GTK_WINDOW(omp_main_window), _("Media Player"));
-	gtk_container_add(GTK_CONTAINER(omp_main_window), GTK_WIDGET(bg_muxer));
-	g_signal_connect(G_OBJECT(omp_main_window), "destroy", G_CALLBACK(omp_main_quit), NULL);
-
-	// Background image
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	container_add_image(GTK_CONTAINER(alignment), "background.png");
-	gtk_fixed_put(GTK_FIXED(bg_muxer), GTK_WIDGET(alignment), 15, 30);
-	
-	// Create all widgets
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	omp_main_widgets_create(GTK_CONTAINER(alignment));
-	gtk_fixed_put(GTK_FIXED(bg_muxer), GTK_WIDGET(alignment), 20, 47);
-
-	// Show everything but the window itself
-	gtk_widget_show_all(GTK_WIDGET(bg_muxer));
-
-	return;
-}
-
-/**
- * Attaches the event handlers to the appropriate signals
- * @note Can't be done in omp_main_window_create() because the signals need to be created
- * @note first by the subsystems which in turn need the main window handle for creating them
- */
-void
-omp_main_connect_signals()
-{
-	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED,			G_CALLBACK(omp_main_update_track_change), NULL);
-	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED,		G_CALLBACK(omp_main_update_status_change), NULL);
-	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED,	G_CALLBACK(omp_main_update_track_position), NULL);
-}
-
-/**
- * Evaluates current track information and updates the config/UI if necessary
- * @note This function only checks elements that don't change too often - for the rest we have specialized functions below
- */
-void
-omp_main_update_track_change()
-{
-	static gint old_track_count = 0;
-	static gint old_track_id = 0;
-	static gulong old_track_length = 0;
-
-	gulong track_length, track_position;
-	gchar *text;
-
-	// Track id/track count changed?
-	if ( (omp_playlist_track_count != old_track_count) || (omp_playlist_current_track_id != old_track_id) )
-	{
-		old_track_count = omp_playlist_track_count;
-		old_track_id = omp_playlist_current_track_id;
-
-		// Update session
-		omp_session_set_track_id(omp_playlist_current_track_id);
-
-		// Update label
-		text = g_strdup_printf(WIDGET_CAPTION_TRACK_NUM, omp_playlist_current_track_id+1, omp_playlist_track_count);
-		gtk_label_set_text(GTK_LABEL(main_widgets.track_number_label), text);
-		g_free(text);
-	}
-
-	// Got a track length change?
-	track_length = omp_playback_get_track_length();
-
-	if (track_length != old_track_length)
-	{
-		old_track_length = track_length;
-		track_position = omp_playback_get_track_position();
-
-		// Set new time slider increments: one tap is 10% of the track's playing time
-		gtk_range_set_increments(GTK_RANGE(main_widgets.time_hscale), track_length/10, track_length/10);
-
-		// Update label and slider
-		text = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME,
-			track_position / 60, track_position % 60,
-			track_length / 60, track_length % 60);
-		gtk_label_set_text(GTK_LABEL(main_widgets.time_label), text);
-		g_free(text);
-
-		if (omp_main_time_slider_can_update)
-		{
-			// We don't want to set both min/max to 0 as this triggers a critial GTK warning, so we set 0/1 instead in that case
-			gtk_range_set_range(GTK_RANGE(main_widgets.time_hscale), 0, track_length ? track_length : 1);
-			gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), track_position);
-		}
-	}
-}
-
-/**
- * Updates the UI if playback engine switched between paused and playing modes
- */
-void
-omp_main_update_status_change()
-{
-	// Update Play/Pause button pixmap
-	if (omp_playback_get_state() == OMP_PLAYBACK_STATE_PAUSED)
-	{
-		gtk_image_set_from_icon_name(GTK_IMAGE(main_widgets.play_pause_button_image), "gtk-media-play-ltr", OMP_BUTTON_PIXMAP_SIZE);
-	} else {
-		gtk_image_set_from_icon_name(GTK_IMAGE(main_widgets.play_pause_button_image), "gtk-media-pause", OMP_BUTTON_PIXMAP_SIZE);
-	}
-}
-
-/**
- * Updates the UI if the playback position changed
- */
-void
-omp_main_update_track_position()
-{
-	static gulong old_track_position = 0;
-
-	gulong track_position, track_length;
-	gchar *text;
-
-	// Got a track length change?
-	track_position = omp_playback_get_track_position();
-	{
-		old_track_position = track_position;
-		track_length = omp_playback_get_track_length();
-
-		// Update UI
-		text = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME,
-			track_position / 60, track_position % 60,
-			track_length / 60, track_length % 60);
-		gtk_label_set_text(GTK_LABEL(main_widgets.time_label), text);
-		g_free(text);
-
-		if (omp_main_time_slider_can_update)
-		{
-			// We don't want to set both min/max to 0 as this triggers a critial GTK warning, so we set 0/1 instead in that case
-			gtk_range_set_range(GTK_RANGE(main_widgets.time_hscale), 0, track_length ? track_length : 1);
-			gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), track_position);
-		}
-	}
-
-}
-

Deleted: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -1,53 +0,0 @@
-/*
- *  OpenMoko Media Player
- *   http://openmoko.org/
- *
- *  Copyright (C) 2007 by the OpenMoko team
- *
- *  This program 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 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program 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, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/**
- * @file mainwin.h
- * Main window handling
- */
-
-#ifndef _MAINWIN_H
-#define _MAINWIN_H
-
-#include <gtk/gtk.h>
-
-#define WIDGET_CAPTION_TRACK_TIME "%d:%.2d / %d:%.2d"
-#define WIDGET_CAPTION_TRACK_NUM "%.3d / %.3d"
-#define WIDGET_CAPTION_VOLUME "%d%%"
-
-// Determines how many seconds the engine will seek if the FFWD/REW buttons are clicked
-#define BUTTON_SEEK_DISTANCE 10
-
-
-extern GtkWidget *omp_main_window;
-
-void omp_application_terminate();
-
-void omp_main_window_show();
-void omp_main_window_hide();
-void omp_main_window_create();
-void omp_main_connect_signals();
-
-void omp_main_update_track_change();
-void omp_main_update_status_change();
-void omp_main_update_track_position();
-
-#endif

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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -51,6 +51,7 @@
 struct _omp_session *omp_session = NULL;		///< Global and persistent session data
 
 
+
 /**
  * Load application configuration data
  */
@@ -150,8 +151,8 @@
 	gint session_file, result;
 	gchar *file_name;
 
-	// OMP_SESSION_FILE_NAME is relative to user's home dir
-	file_name = g_build_filename(g_get_home_dir(), OMP_SESSION_FILE_NAME, NULL);
+	// SESSION_FILE_NAME is relative to user's home dir
+	file_name = g_build_filename(g_get_home_dir(), SESSION_FILE_NAME, NULL);
 
 	// Permissions for created session file are 0600
 	session_file = creat(file_name, S_IRUSR | S_IWUSR);
@@ -184,8 +185,8 @@
 	gint session_file, result;
 	gchar *file_name;
 
-	// OMP_SESSION_FILE_NAME is relative to user's home dir
-	file_name = g_build_filename(g_get_home_dir(), OMP_SESSION_FILE_NAME, NULL);
+	// SESSION_FILE_NAME is relative to user's home dir
+	file_name = g_build_filename(g_get_home_dir(), SESSION_FILE_NAME, NULL);
 
 	session_file = open(file_name, O_RDONLY);
 	if (session_file == -1) goto io_error;

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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -24,15 +24,12 @@
  * Manages application configuration and session data
  */
 
-#ifndef _PERSISTENT_H
-#define _PERSISTENT_H
+#ifndef PERSISTENT_H
+#define PERSISTENT_H
 
 #include "playlist.h"
+#include "main.h"
 
-// File name is relative to ~
-#define OMP_SESSION_FILE_NAME "/.openmoko-mediaplayer"
-
-
 /// Application configuration data
 struct _omp_config
 {

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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -27,7 +27,7 @@
 #include <gst/gst.h>
 
 #include "playback.h"
-#include "mainwin.h"
+#include "main.h"
 
 GstElement *omp_gst_playbin = NULL;						///< Our ticket to the gstreamer world
 guint omp_playback_ui_timeout = 0;						///< Handle of the UI-updating timeout
@@ -35,6 +35,7 @@
 gulong omp_playback_pending_position = 0;			///< Since we can't set a new position if element is not paused or playing we store the position here and set it when it reached either state
 
 
+
 /**
  * Initializes gstreamer by setting up pipe, message hooks and bins
  */
@@ -131,7 +132,7 @@
 static gboolean
 omp_playback_ui_timeout_callback(gpointer data)
 {
-	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
+	g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
 	
 	if (omp_playback_ui_timeout_halted)
 	{
@@ -168,14 +169,12 @@
 	// Set state
 	gst_element_set_state(omp_gst_playbin, GST_STATE_PLAYING);
 
-	// Add timer to update UI if necessary
-	// If the halt flag was set but the callback didn't run yet then we
-	// don't want to add another callback since we would have two then
+	// Add timer to update UI if it isn't already there
 	omp_playback_ui_timeout_halted = FALSE;
 
 	if (!omp_playback_ui_timeout)
 	{
-		omp_playback_ui_timeout = g_timeout_add(OMP_PLAYBACK_UI_UPDATE_INTERVAL, omp_playback_ui_timeout_callback, NULL);
+		omp_playback_ui_timeout = g_timeout_add(PLAYBACK_UI_UPDATE_INTERVAL, omp_playback_ui_timeout_callback, NULL);
 	}
 }
 
@@ -274,7 +273,7 @@
 		GST_SEEK_TYPE_SET, position*GST_SECOND,
 		GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
 
-	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
+	g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
 }
 
 /**
@@ -309,7 +308,7 @@
 	gst_element_set_state(omp_gst_playbin, GST_STATE_READY);
 	omp_playback_set_track_position(0);
 
-	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_EOS);
+	g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYBACK_EOS);
 
 	return TRUE;
 }
@@ -335,7 +334,7 @@
 	if (new_state != previous_state)
 	{
 		previous_state = new_state;
-		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED);
+		g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED);
 	}
 }
 

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -24,8 +24,8 @@
  * Playback engine interface
  */
 
-#ifndef _PLAYBACK_H
-#define _PLAYBACK_H
+#ifndef PLAYBACK_H
+#define PLAYBACK_H
 
 #include <gst/gst.h>
 
@@ -38,7 +38,7 @@
 #define OMP_PLAYBACK_STATE_PLAYING GST_STATE_PLAYING
 
 // The UI will be updated at this interval when a track is playing (in ms)
-#define OMP_PLAYBACK_UI_UPDATE_INTERVAL 1000
+#define PLAYBACK_UI_UPDATE_INTERVAL 1000
 
 void omp_playback_init();
 void omp_playback_free();

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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -30,7 +30,7 @@
 #include <spiff/spiff_c.h>
 
 #include "playlist.h"
-#include "mainwin.h"
+#include "main.h"
 #include "playback.h"
 #include "persistent.h"
 
@@ -59,7 +59,7 @@
 omp_playlist_init()
 {
 	// Hook up event handlers to the playback routines
-	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_EOS, G_CALLBACK(omp_playlist_process_eos_event), NULL);
+	g_signal_connect(G_OBJECT(omp_window), OMP_EVENT_PLAYBACK_EOS, G_CALLBACK(omp_playlist_process_eos_event), NULL);
 
 	// Create the signals we emit: no params, no return value
 	g_signal_new(OMP_EVENT_PLAYLIST_TRACK_CHANGED, G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
@@ -156,7 +156,7 @@
 		omp_playlist_track_count = track_num;
 
 		// Emit signal to update UI and the like
-		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
+		g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
 	}
 
 	return position_valid;
@@ -247,7 +247,7 @@
 	if (is_new_track)
 	{
 		// Emit signal to update UI and the like
-		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
+		g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
 
 		// Load track and start playing if needed
 		if (omp_playlist_load_current_track())
@@ -309,7 +309,7 @@
 		omp_track_history = g_slist_prepend(omp_track_history, (gpointer)history_entry);
 
 		// Emit signal to update UI and the like
-		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
+		g_signal_emit_by_name(G_OBJECT(omp_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
 
 		// Load track and start playing if needed
 		if (omp_playlist_load_current_track())

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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -24,8 +24,8 @@
  * Playlist handling
  */
 
-#ifndef _PLAYLIST_H
-#define _PLAYLIST_H
+#ifndef PLAYLIST_H
+#define PLAYLIST_H
 
 #include <spiff/spiff_c.h>
 

Added: 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-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.c	2007-08-09 12:44:25 UTC (rev 2669)
@@ -0,0 +1,115 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file playlist_page.c
+ * Playlist UI handling
+ */
+
+#include <gtk/gtk.h>
+#include <libmokoui2/moko-finger-scroll.h>
+
+#include "playlist_page.h"
+#include "main.h"
+
+/// Enumeration for the list columns
+enum
+{
+	ICON_COLUMN,
+	NAME_COLUMN,
+	ACTION_COLUMN,
+	COLUMN_COUNT
+};
+
+/// The input field where a new playlist name is entered
+GtkWidget *omp_playlist_page_entry;
+
+/**
+ * Creates the playlist view
+ */
+void
+omp_playlist_page_list_create(GtkContainer *container)
+{
+	GtkListStore *store;
+	GtkWidget *tree_view;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	// Create and populate data model
+	store = gtk_list_store_new(1, G_TYPE_STRING);
+
+	// Create data view
+	tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+
+	renderer = gtk_cell_renderer_pixbuf_new();
+	column = gtk_tree_view_column_new_with_attributes("", renderer, NULL);
+	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+	gtk_tree_view_column_set_fixed_width(column, BUTTON_PIXMAP_SIZE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes("Playlist Name", renderer,
+		"name", 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();
+	column = gtk_tree_view_column_new_with_attributes("Actions", renderer, NULL);
+	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+	gtk_tree_view_column_set_fixed_width(column, 2*BUTTON_PIXMAP_SIZE+10);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+
+	// Add view to container
+	gtk_container_add(container, GTK_WIDGET(tree_view));
+}
+
+/**
+ * Create the playlist UI page and all its elements
+ */
+GtkWidget *
+omp_playlist_page_create(GtkWindow *window)
+{
+	GtkWidget *main_vbox, *scroll_box, *input_box, *button, *image;
+
+	// Create main container
+	main_vbox = gtk_vbox_new(FALSE, 0);
+
+	scroll_box = moko_finger_scroll_new();
+	gtk_box_pack_start(GTK_BOX(main_vbox), GTK_WIDGET(scroll_box), TRUE, TRUE, 0);
+
+	// Create playlist view
+	omp_playlist_page_list_create(GTK_CONTAINER(scroll_box));
+
+	// Add entry field for creation of a new playlist
+	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", BUTTON_PIXMAP_SIZE);
+	gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
+
+	gtk_box_pack_start(GTK_BOX(input_box), GTK_WIDGET(omp_playlist_page_entry), TRUE, TRUE, 5);
+	gtk_box_pack_start(GTK_BOX(input_box), GTK_WIDGET(button), FALSE, TRUE, 5);
+
+	gtk_box_pack_start(GTK_BOX(main_vbox), GTK_WIDGET(input_box), FALSE, TRUE, 10);
+
+	return main_vbox;
+}
+

Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.h	2007-08-09 11:16:08 UTC (rev 2668)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist_page.h	2007-08-09 12:44:25 UTC (rev 2669)
@@ -0,0 +1,35 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file playlist_page.h
+ * Playlist UI handling
+ */
+
+#ifndef PLAYLIST_PAGE_H
+#define PLAYLIST_PAGE_H
+
+#include <gtk/gtk.h>
+
+GtkWidget *omp_playlist_page_create();
+void omp_playlist_connect_signals();
+
+#endif





More information about the commitlog mailing list