--- Begin Message ---
Author: mickey
Date: 2007-08-04 12:36:33 +0200 (Sat, 04 Aug 2007)
New Revision: 2630
Added:
trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.c
trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.h
Modified:
trunk/src/target/OM-2007.2/daemons/neod/AUTHORS
trunk/src/target/OM-2007.2/daemons/neod/README
trunk/src/target/OM-2007.2/daemons/neod/configure.ac
trunk/src/target/OM-2007.2/daemons/neod/src/Makefile.am
trunk/src/target/OM-2007.2/daemons/neod/src/neod-main.c
Log:
neod: extract basic functionality out of former openmoko-panel-mainmenu
Modified: trunk/src/target/OM-2007.2/daemons/neod/AUTHORS
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/AUTHORS 2007-08-04 06:02:22 UTC
(rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/AUTHORS 2007-08-04 10:36:33 UTC
(rev 2630)
@@ -0,0 +1,2 @@
+Michael Lauer <[EMAIL PROTECTED]>
+
Modified: trunk/src/target/OM-2007.2/daemons/neod/README
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/README 2007-08-04 06:02:22 UTC
(rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/README 2007-08-04 10:36:33 UTC
(rev 2630)
@@ -0,0 +1,7 @@
+Minimal Button and powermanagement handling daemon
+
+NOTE: Merely throwaway code, since it may be a better idea to base on
+ * HAL / OHM, or
+ * devmand, or
+ * zaurusd ?
+
Modified: trunk/src/target/OM-2007.2/daemons/neod/configure.ac
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/configure.ac 2007-08-04
06:02:22 UTC (rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/configure.ac 2007-08-04
10:36:33 UTC (rev 2630)
@@ -21,6 +21,7 @@
AM_GLIB_GNU_GETTEXT
PKG_CHECK_MODULES(GTK, gtk+-2.0 >= $LIBGTK_VERSION)
+PKG_CHECK_MODULES(PULSE, libpulse)
CFLAGS=$GTK_CFLAGS
AC_CHECK_DECLS([g_date_set_time_t],
Modified: trunk/src/target/OM-2007.2/daemons/neod/src/Makefile.am
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/src/Makefile.am 2007-08-04
06:02:22 UTC (rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/src/Makefile.am 2007-08-04
10:36:33 UTC (rev 2630)
@@ -4,12 +4,15 @@
-DNEOD_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-DDATADIR=\""$(datadir)"\" -D_GNU_SOURCE
-AM_CFLAGS = -Wall -pedantic -std=c99 @GTK_CFLAGS@
+AM_CFLAGS = -Wall -pedantic -std=c99 @GTK_CFLAGS@ @PULSE_CFLAGS@
bin_PROGRAMS = neod
neod_SOURCES = \
- neod-main.c
+ buttonactions.c \
+ neod-main.c
+neod_LDADD = @GTK_LIBS@ @PULSE_LIBS@
+
MAINTAINERCLEANFILES = config.h.in Makefile.in
Added: trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.c
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.c 2007-08-04
06:02:22 UTC (rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.c 2007-08-04
10:36:33 UTC (rev 2630)
@@ -0,0 +1,525 @@
+/*
+ * Authored by Michael 'Mickey' Lauer <[EMAIL PROTECTED]>
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Public License as published by
+ * the Free Software Foundation; version 2 of the license.
+ *
+ * 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 Public License for more details.
+ */
+#include "buttonactions.h"
+
+#include <gtk/gtklabel.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+
+#include <gdk/gdkx.h>
+
+#include <glib.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include <pulse/pulseaudio.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/input.h>
+
+#undef DEBUG_THIS_FILE
+//#define DEBUG_THIS_FILE
+
+//FIXME load this from sysfs
+static const int MAX_BRIGHTNESS = 5000;
+
+//FIXME find out through sysfs
+#ifndef DEBUG_THIS_FILE
+ #define AUX_BUTTON_EVENT_PATH "/dev/input/event1"
+ #define AUX_BUTTON_KEYCODE 169
+ #define POWER_BUTTON_EVENT_PATH "/dev/input/event2"
+ #define POWER_BUTTON_KEYCODE 116
+ #define TOUCHSCREEN_EVENT_PATH "/dev/input/touchscreen0"
+ #define TOUCHSCREEN_BUTTON_KEYCODE 0x14a
+#else
+ #define AUX_BUTTON_EVENT_PATH "/dev/input/event1"
+ #define AUX_BUTTON_KEYCODE 0x25
+ #define POWER_BUTTON_EVENT_PATH "/dev/input/event0"
+ #define POWER_BUTTON_KEYCODE 0x25
+ #define TOUCHSCREEN_EVENT_PATH "/dev/input/event2"
+ #define TOUCHSCREEN_BUTTON_KEYCODE 0x14a
+#endif
+
+GPollFD aux_fd;
+GPollFD power_fd;
+GIOChannel* touchscreen_io;
+
+int aux_timer = -1;
+int power_timer = -1;
+int powersave_timer1 = -1;
+int powersave_timer2 = -1;
+int powersave_timer3 = -1;
+
+GtkWidget* aux_menu = 0;
+GtkWidget* power_menu = 0;
+
+typedef enum _PowerState
+{
+ NORMAL,
+ DISPLAY_DIM,
+ DISPLAY_OFF,
+ SUSPEND,
+} PowerState;
+PowerState power_state = NORMAL;
+
+static pa_context* pac;
+
+/* Borrowed from libwnck */
+static Window get_window_property( Window xwindow, Atom atom )
+{
+ Atom type;
+ int format;
+ gulong nitems;
+ gulong bytes_after;
+ Window *w;
+ int err, result;
+ Window retval;
+
+ gdk_error_trap_push ();
+
+ type = None;
+ result = XGetWindowProperty (gdk_display,
+ xwindow,
+ atom,
+ 0, G_MAXLONG,
+ False, XA_WINDOW, &type, &format, &nitems,
+ &bytes_after, (unsigned char **) &w);
+ err = gdk_error_trap_pop ();
+
+ if (err != Success ||
+ result != Success)
+ return None;
+
+ if (type != XA_WINDOW)
+ {
+ XFree (w);
+ return None;
+ }
+
+ retval = *w;
+ XFree (w);
+
+ return retval;
+}
+
+gboolean neod_buttonactions_install_watcher()
+{
+ int auxfd = open( AUX_BUTTON_EVENT_PATH, O_RDONLY );
+ if ( auxfd < 0 )
+ {
+ g_debug( "can't open " AUX_BUTTON_EVENT_PATH " (%s)", strerror( errno
) );
+ return FALSE;
+ }
+ int powerfd = open( POWER_BUTTON_EVENT_PATH, O_RDONLY );
+ if ( powerfd < 0 )
+ {
+ g_debug( "can't open " POWER_BUTTON_EVENT_PATH " (%s)", strerror(
errno ) );
+ return FALSE;
+ }
+ static GSourceFuncs funcs = {
+ neod_buttonactions_input_prepare,
+ neod_buttonactions_input_check,
+ neod_buttonactions_input_dispatch,
+ NULL,
+ };
+ GSource* button_watcher = g_source_new( &funcs, sizeof (GSource) );
+ aux_fd.fd = auxfd;
+ aux_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ aux_fd.revents = 0;
+ g_source_add_poll( button_watcher, &aux_fd );
+ power_fd.fd = powerfd;
+ power_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ power_fd.revents = 0;
+ g_source_add_poll( button_watcher, &power_fd );
+ g_source_attach( button_watcher, NULL );
+
+ if ( getenv( "MOKO_POWERSAVE" ) != NULL )
+ {
+
+ int tsfd = open( TOUCHSCREEN_EVENT_PATH, O_RDONLY );
+ if ( tsfd < 0 )
+ {
+ g_debug( "can't open " TOUCHSCREEN_EVENT_PATH " (%s)", strerror(
errno ) );
+ return FALSE;
+ }
+ touchscreen_io = g_io_channel_unix_new( tsfd );
+ g_io_add_watch( touchscreen_io, G_IO_IN,
neod_buttonactions_touchscreen_cb, NULL );
+
+ neod_buttonactions_powersave_reset();
+ neod_buttonactions_set_display( 100 );
+ neod_buttonactions_sound_init();
+ }
+ else
+ g_debug( "MOKO_POWERSAVE=yes not set. Not enabling power management."
);
+
+ return TRUE;
+}
+
+
+gboolean neod_buttonactions_input_prepare( GSource* source, gint* timeout )
+{
+ return FALSE;
+}
+
+
+gboolean neod_buttonactions_input_check( GSource* source )
+{
+ return ( ( aux_fd.revents & G_IO_IN ) || ( power_fd.revents & G_IO_IN ) );
+}
+
+
+gboolean neod_buttonactions_input_dispatch( GSource* source, GSourceFunc
callback, gpointer data )
+{
+ if ( aux_fd.revents & G_IO_IN )
+ {
+ struct input_event event;
+ int size = read( aux_fd.fd, &event, sizeof( struct input_event ) );
+ //g_debug( "read %d bytes from aux_fd %d", size, aux_fd.fd );
+ //g_debug( "input event = ( %0x, %0x, %0x )", event.type, event.code,
event.value );
+ if ( event.type == 1 && event.code == AUX_BUTTON_KEYCODE )
+ {
+ if ( event.value == 1 ) /* pressed */
+ {
+ g_debug( "triggering aux timer" );
+ aux_timer = g_timeout_add( 1 * 1000, (GSourceFunc)
neod_buttonactions_aux_timeout, (gpointer)1 );
+ }
+ else if ( event.value == 0 ) /* released */
+ {
+ g_debug( "resetting aux timer" );
+ if ( aux_timer != -1 )
+ {
+ g_source_remove( aux_timer );
+ neod_buttonactions_aux_timeout( 0 );
+ }
+ aux_timer = -1;
+ }
+ }
+ }
+ if ( power_fd.revents & G_IO_IN )
+ {
+ struct input_event event;
+ int size = read( power_fd.fd, &event, sizeof( struct input_event ) );
+ //g_debug( "read %d bytes from power_fd %d", size, power_fd.fd );
+ //g_debug( "input event = ( %0x, %0x, %0x )", event.type, event.code,
event.value );
+ if ( event.type == 1 && event.code == POWER_BUTTON_KEYCODE )
+ {
+ if ( event.value == 1 ) /* pressed */
+ {
+ g_debug( "triggering power timer" );
+ power_timer = g_timeout_add( 1 * 1000, (GSourceFunc)
neod_buttonactions_power_timeout, (gpointer)1 );
+ }
+ else if ( event.value == 0 ) /* released */
+ {
+ g_debug( "resetting power timer" );
+ if ( power_timer != -1 )
+ {
+ g_source_remove( power_timer );
+ neod_buttonactions_power_timeout( 0 );
+ }
+ power_timer = -1;
+ }
+ }
+ }
+ return TRUE;
+}
+
+gboolean neod_buttonactions_aux_timeout( guint timeout )
+{
+ g_debug( "aux pressed for %d", timeout );
+
+ neod_buttonactions_sound_play( "touchscreen" );
+ neod_buttonactions_powersave_reset();
+
+ aux_timer = -1;
+ if ( timeout < 1 )
+ {
+ // make dialer interface show up
+ // NOTE: temporary hack, will use dbus interface once dialer has it :)
+ system( "openmoko-dialer &" );
+ }
+ else
+ {
+ // make main menu show up
+ // NOTE: temporary hack, will use dbus interface once main menu has it
:)
+ system( "openmoko-mainmenu &" );
+ }
+ return FALSE;
+}
+
+// this is hardcoded to the Neo1973
+void neod_buttonactions_popup_positioning_cb( GtkMenu* menu, gint* x, gint* y,
gboolean* push_in, gpointer user_data )
+{
+ GtkRequisition req;
+ gtk_widget_size_request( GTK_WIDGET(menu), &req );
+ gint screen_width = gdk_screen_width();
+ gint screen_height = gdk_screen_height();
+
+ if ( GTK_WIDGET(menu) == aux_menu )
+ {
+ *x = 0;
+ *y = 0;
+ }
+ else if ( GTK_WIDGET(menu) == power_menu )
+ {
+ *x = screen_width - req.width;
+ *y = screen_height - req.height;
+ }
+ else
+ g_assert( FALSE ); // fail here if called for unknown menu
+}
+
+void neod_buttonactions_popup_selected_lock( GtkMenuItem* menu, gpointer
user_data )
+{
+ //FIXME talk to neod
+ int fd = open( "/sys/power/state", O_WRONLY );
+ if ( fd != -1 )
+ {
+ char command[] = "mem\n";
+ write(fd, &command, sizeof(command) );
+ close( fd );
+ }
+}
+
+void neod_buttonactions_popup_selected_restartUI( GtkMenuItem* menu, gpointer
user_data )
+{
+ //FIXME talk to neod
+ //FIXME notify user
+ system( "/etc/init.d/xserver-nodm restart");
+}
+
+void neod_buttonactions_popup_selected_reboot( GtkMenuItem* menu, gpointer
user_data )
+{
+ //FIXME talk to neod
+ //moko_ui_banner_show_text( 4, "Rebooting System..." );
+ system( "/sbin/reboot");
+}
+
+void neod_buttonactions_popup_selected_poweroff( GtkMenuItem* menu, gpointer
user_data )
+{
+ //FIXME talk to neod
+ //moko_ui_banner_show_text( 4, "Shutting down System..." );
+ system( "/sbin/poweroff");
+}
+
+gboolean neod_buttonactions_power_timeout( guint timeout )
+{
+ g_debug( "power pressed for %d", timeout );
+
+ neod_buttonactions_sound_play( "touchscreen" );
+ neod_buttonactions_powersave_reset();
+
+ power_timer = -1;
+ if ( timeout < 1 )
+ {
+ Window xwindow = get_window_property(
gdk_x11_get_default_root_xwindow(),
gdk_x11_get_xatom_by_name("_NET_ACTIVE_WINDOW") );
+ g_debug( "active Window = %d", (int) xwindow );
+
+ Display* display = XOpenDisplay( NULL );
+
+ //xwindow = gdk_x11_drawable_get_xid (window);
+
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = display;
+ xev.xclient.window = xwindow;
+ xev.xclient.message_type = gdk_x11_get_xatom_by_name(
"_NET_CLOSE_WINDOW" );
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = 0;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ //TODO: add timeout checking for response
+
+ XSendEvent (display, gdk_x11_get_default_root_xwindow (), False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ XCloseDisplay( display );
+
+ }
+ else
+ {
+ // show popup menu requesting for actions
+ if ( !power_menu )
+ {
+ power_menu = gtk_menu_new();
+ GtkWidget* lock = gtk_menu_item_new_with_label( "Lock" );
+ g_signal_connect( G_OBJECT(lock), "activate",
G_CALLBACK(neod_buttonactions_popup_selected_lock), NULL );
+ gtk_menu_shell_append( GTK_MENU_SHELL(power_menu), lock );
+ GtkWidget* flightmode = gtk_menu_item_new_with_label( "Flight
Mode" );
+ gtk_menu_shell_append( GTK_MENU_SHELL(power_menu), flightmode );
+ GtkWidget* profilelist = gtk_menu_item_new_with_label( "<Profile
List>" );
+ gtk_menu_shell_append( GTK_MENU_SHELL(power_menu), profilelist );
+ GtkWidget* restartUI = gtk_menu_item_new_with_label( "Restart UI"
);
+ g_signal_connect( G_OBJECT(restartUI), "activate",
G_CALLBACK(neod_buttonactions_popup_selected_restartUI), NULL );
+ GtkWidget* reboot = gtk_menu_item_new_with_label( "Reboot" );
+ g_signal_connect( G_OBJECT(reboot), "activate",
G_CALLBACK(neod_buttonactions_popup_selected_reboot), NULL );
+ GtkWidget* poweroff = gtk_menu_item_new_with_label( "Power Off" );
+ g_signal_connect( G_OBJECT(poweroff), "activate",
G_CALLBACK(neod_buttonactions_popup_selected_poweroff), NULL );
+ gtk_menu_shell_append( GTK_MENU_SHELL(power_menu), poweroff );
+ gtk_widget_show_all( GTK_WIDGET(power_menu) );
+ }
+ gtk_menu_popup( GTK_MENU(power_menu), NULL, NULL,
neod_buttonactions_popup_positioning_cb, 0, 0, GDK_CURRENT_TIME );
+ }
+ return FALSE;
+}
+
+gboolean neod_buttonactions_touchscreen_cb( GIOChannel *source, GIOCondition
condition, gpointer data )
+{
+ g_debug( "mainmenu touchscreen event" );
+
+ struct input_event event;
+ int size = read( g_io_channel_unix_get_fd( source ), &event, sizeof(
struct input_event ) );
+
+ if ( event.type == 1 && event.code == TOUCHSCREEN_BUTTON_KEYCODE )
+ {
+ if ( event.value == 1 ) /* pressed */
+ {
+ g_debug( "stylus pressed" );
+ neod_buttonactions_sound_play( "touchscreen" );
+ }
+ else if ( event.value == 0 ) /* released */
+ {
+ g_debug( "stylus released" );
+ }
+
+ neod_buttonactions_powersave_reset();
+ if ( power_state != NORMAL )
+ {
+ neod_buttonactions_set_display( 100 );
+ power_state = NORMAL;
+ }
+ }
+ return TRUE;
+}
+
+void neod_buttonactions_powersave_reset()
+{
+ g_debug( "mainmenu powersave reset" );
+ if ( powersave_timer1 != -1 )
+ g_source_remove( powersave_timer1 );
+ if ( powersave_timer2 != -1 )
+ g_source_remove( powersave_timer2 );
+ if ( powersave_timer3 != -1 )
+ g_source_remove( powersave_timer3 );
+
+ //TODO load this from preferences
+ powersave_timer1 = g_timeout_add( 10 * 1000, (GSourceFunc)
neod_buttonactions_powersave_timeout1, (gpointer)1 );
+ powersave_timer2 = g_timeout_add( 20 * 1000, (GSourceFunc)
neod_buttonactions_powersave_timeout2, (gpointer)1 );
+ powersave_timer3 = g_timeout_add( 60 * 5 * 1000, (GSourceFunc)
neod_buttonactions_powersave_timeout3, (gpointer)1 );
+}
+
+void neod_buttonactions_set_display( int brightness )
+{
+ g_debug( "mainmenu set display %d", brightness );
+ int fd = g_open( "/sys/class/backlight/gta01-bl/brightness", O_WRONLY, 0 );
+ if ( fd == -1 )
+ g_debug( "can't open backlight device: %s", strerror( errno ) );
+ else
+ {
+ char buf[10];
+ int numbytes = g_sprintf( buf, "%d\0", MAX_BRIGHTNESS / 100 *
(brightness+1 ) );
+ write( fd, buf, numbytes );
+ close( fd );
+ }
+}
+
+gboolean neod_buttonactions_powersave_timeout1( guint timeout )
+{
+ g_debug( "mainmenu powersave timeout 1" );
+ //FIXME talk to neod
+ power_state = DISPLAY_DIM;
+ neod_buttonactions_set_display( 25 );
+ return FALSE;
+}
+
+gboolean neod_buttonactions_powersave_timeout2( guint timeout )
+{
+ g_debug( "mainmenu powersave timeout 2" );
+ //FIXME talk to neod
+ neod_buttonactions_set_display( 0 );
+ power_state = DISPLAY_OFF;
+ return FALSE;
+}
+
+gboolean neod_buttonactions_powersave_timeout3( guint timeout )
+{
+ g_debug( "mainmenu powersave timeout 3" );
+ //FIXME talk to neod
+ power_state = SUSPEND;
+ system( "/usr/bin/apm -s");
+ neod_buttonactions_powersave_reset();
+ neod_buttonactions_set_display( 100 );
+ power_state = NORMAL;
+ return FALSE;
+}
+
+void neod_buttonactions_sound_state_cb( pa_context* pac, void* userdata )
+{
+ g_debug( "mainmenu sound state callback. state = %d",
pa_context_get_state( pac ) );
+ if ( pa_context_get_state( pac ) == PA_CONTEXT_READY )
+ {
+ neod_buttonactions_sound_play( "startup" );
+ }
+}
+
+void neod_buttonactions_sound_init()
+{
+ g_debug( "panel mainmenu sound init" );
+ pa_threaded_mainloop* mainloop = pa_threaded_mainloop_new();
+
+ if ( !mainloop )
+ {
+ printf( "couldn't create mainloop: %s", strerror( errno ) );
+ return;
+ }
+
+ pa_mainloop_api* mapi = pa_threaded_mainloop_get_api( mainloop );
+
+ pac = pa_context_new( mapi, "test client" );
+ if ( !pac )
+ {
+ printf( "couldn't create pa_context: %s", strerror( errno ) );
+ return;
+ }
+
+ pa_context_set_state_callback( pac, neod_buttonactions_sound_state_cb,
NULL );
+ pa_context_connect( pac, NULL, 0, NULL );
+ pa_threaded_mainloop_start( mainloop );
+
+ g_debug( "sound init ok. threaded mainloop started" );
+}
+
+void neod_buttonactions_sound_play( const gchar* samplename )
+{
+ g_return_if_fail( pac );
+ pa_context_play_sample( pac,
+ samplename, // Name of my sample
+ NULL, // Use default sink
+ PA_VOLUME_NORM, // Full volume
+ NULL, // Don't need a callback
+ NULL
+ );
+
+}
Property changes on: trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.h
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.h 2007-08-04
06:02:22 UTC (rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.h 2007-08-04
10:36:33 UTC (rev 2630)
@@ -0,0 +1,40 @@
+/*
+ * Authored by Michael 'Mickey' Lauer <[EMAIL PROTECTED]>
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Public License as published by
+ * the Free Software Foundation; version 2.1 of the license.
+ *
+ * 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 Public License for more details.
+ */
+#ifndef BUTTONACTIONS_H
+#define BUTTONACTIONS_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+gboolean neod_buttonactions_input_prepare( GSource* source, gint* timeout );
+gboolean neod_buttonactions_input_check( GSource* source );
+gboolean neod_buttonactions_input_dispatch( GSource* source, GSourceFunc
callback, gpointer data );
+
+gboolean neod_buttonactions_touchscreen_cb( GIOChannel *source, GIOCondition
condition, gpointer data );
+
+gboolean neod_buttonactions_aux_timeout( guint timeout );
+gboolean neod_buttonactions_power_timeout( guint timeout );
+
+void neod_buttonactions_powersave_reset();
+
+gboolean neod_buttonactions_powersave_timeout1( guint timeout );
+gboolean neod_buttonactions_powersave_timeout2( guint timeout );
+gboolean neod_buttonactions_powersave_timeout3( guint timeout );
+
+void neod_buttonactions_sound_init();
+void neod_buttonactions_set_display( int brightness );
+void neod_buttonactions_sound_play( const gchar* samplename );
+
+#endif
Property changes on: trunk/src/target/OM-2007.2/daemons/neod/src/buttonactions.h
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: trunk/src/target/OM-2007.2/daemons/neod/src/neod-main.c
===================================================================
--- trunk/src/target/OM-2007.2/daemons/neod/src/neod-main.c 2007-08-04
06:02:22 UTC (rev 2629)
+++ trunk/src/target/OM-2007.2/daemons/neod/src/neod-main.c 2007-08-04
10:36:33 UTC (rev 2630)
@@ -1,5 +1,28 @@
+/*
+ * Authored by Michael 'Mickey' Lauer <[EMAIL PROTECTED]>
+ *
+ * Copyright (C) 2006-2007 OpenMoko Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Public License as published by
+ * the Free Software Foundation; version 2 of the license.
+ *
+ * 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 Public License for more details.
+ */
+
+#include "buttonactions.h"
+
+#include <gtk/gtk.h>
+
int main( int argc, char** argv )
{
+ //FIXME add daemonizing
+ gtk_init( &argc, &argv );
+
+ gtk_main();
return 1;
}
--- End Message ---
--- Begin Message ---
Author: abraxa
Date: 2007-08-04 14:50:34 +0200 (Sat, 04 Aug 2007)
New Revision: 2631
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h
Log:
Continued work on UI<->backend communication and gstreamer wrapping
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am
===================================================================
---
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am
2007-08-04 10:36:33 UTC (rev 2630)
+++
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am
2007-08-04 12:50:34 UTC (rev 2631)
@@ -17,7 +17,8 @@
$(OPENMOKO_CFLAGS) \
$(OMP_DEFINES) \
-I$(top_srcdir) \
- -I$(top_srcdir)/intl
+ -I$(top_srcdir)/intl\
+ -g -DDEBUG
INCLUDES = $(openmoko_mediaplayer_CFLAGS)
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c
2007-08-04 12:50:34 UTC (rev 2631)
@@ -140,6 +140,10 @@
void
omp_config_restore_state()
{
+ #ifdef DEBUG
+ g_print("Loading playlist and restoring playback state\n");
+ #endif
+
// This mustn't be called more than once
g_assert(omp_config == NULL);
@@ -158,10 +162,11 @@
// Check whether playlist_position is valid
if (!omp_playlist_set_current_track(omp_config->playlist_position))
{
- // Reset playlist state as it must have been modified since it
was last loaded
+ // Reset playlist state as playlist must have been modified
since it was last loaded
omp_config->playlist_position = 0;
omp_config->track_position = 0;
- }
+ omp_playlist_set_current_track(0);
+ }
// Feed the track entity to the playback engine to obtain track
information
omp_playlist_load_current_track();
@@ -362,15 +367,12 @@
signal(SIGSEGV, handler_sigsegfault);
signal(SIGUSR1, handler_sigusr1);
- // Load config and restore playback state
- omp_config_restore_state();
-
// Initialize playback, playlist and UI handling
omp_main_window_create();
omp_playback_init();
omp_playlist_init();
omp_main_connect_signals();
- omp_main_update_track_info();
+ omp_config_restore_state();
omp_main_window_show();
gtk_main();
@@ -384,6 +386,7 @@
omp_playback_free();
omp_playlist_free();
gst_deinit();
+ g_free(ui_image_path);
#ifdef DEBUG_MEM_PROFILE
g_mem_profile();
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h
2007-08-04 12:50:34 UTC (rev 2631)
@@ -52,7 +52,7 @@
// gchar *playlist_path; ///<
Last path used for the playlist selection dialog
gchar playlist_file[256]; ///< Path and
file name of current (=last used) playlist
gint playlist_position; ///< Position
within the playlist
- gint track_position; ///<
Position to resume playback from within the last played track
+ glong track_position; ///<
Position to resume playback from within the last played track
};
extern struct _omp_config *omp_config;
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c
2007-08-04 12:50:34 UTC (rev 2631)
@@ -59,6 +59,8 @@
GtkWidget *omp_main_window = NULL;
+gboolean omp_main_time_slider_can_update = TRUE;
+gboolean omp_main_time_slider_was_dragged = FALSE;
/**
@@ -67,9 +69,6 @@
void
omp_application_terminate()
{
- // Free resources
- g_free(ui_image_path);
-
// Tell GTK to leave the message loop
gtk_main_quit();
}
@@ -190,7 +189,52 @@
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)))
@@ -225,13 +269,46 @@
}
/**
+ * 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 State change, etc
+ * @todo Pixmap change
*/
void
omp_main_button_play_pause_callback()
{
- omp_playback_play();
+ if (omp_playback_get_state() != OMP_PLAYBACK_STATE_PLAYING)
+ {
+ omp_playback_play();
+
+ } else {
+
+ omp_playback_pause();
+ }
}
/**
@@ -282,7 +359,6 @@
image = gtk_image_new_from_icon_name(image_name, 36);
gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
- g_object_unref(image);
return button;
}
@@ -388,9 +464,11 @@
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(time_hscale), "change_value",
-// G_CALLBACK(omp_main_set_time), NULL);
+ 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 --- --- --- --- ---
@@ -483,7 +561,7 @@
gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button),
FALSE, FALSE, 0, GTK_PACK_START);
// Rewind button
- button = omp_button_create("gtk-media-rewind-ltr", NULL);
+ button = omp_button_create("gtk-media-rewind-ltr",
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);
@@ -493,7 +571,7 @@
gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button),
FALSE, FALSE, 0, GTK_PACK_START);
// Fast Forward button
- button = omp_button_create("gtk-media-forward-ltr", NULL);
+ button = omp_button_create("gtk-media-forward-ltr",
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);
@@ -536,6 +614,7 @@
// Show everything but the window itself
gtk_widget_show_all(GTK_WIDGET(bg_muxer));
+
return;
}
@@ -547,20 +626,23 @@
void
omp_main_connect_signals()
{
- g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PREV_TRACK,
G_CALLBACK(omp_main_update_track_info), NULL);
- g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_NEXT_TRACK,
G_CALLBACK(omp_main_update_track_info), NULL);
+ 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_track_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_info()
+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?
@@ -572,12 +654,68 @@
// Update config
omp_config_update();
- // Update UI
+ // 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
+ 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)
+ {
+
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 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)
+ {
+
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);
+ }
+ }
+
+}
+
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h
2007-08-04 12:50:34 UTC (rev 2631)
@@ -33,6 +33,9 @@
#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();
@@ -42,6 +45,7 @@
void omp_main_window_create();
void omp_main_connect_signals();
-void omp_main_update_track_info();
+void omp_main_update_track_change();
+void omp_main_update_track_position();
#endif
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c
2007-08-04 12:50:34 UTC (rev 2631)
@@ -30,9 +30,9 @@
#include "mainwin.h"
GstElement *omp_gst_playbin = NULL;
+guint omp_playback_ui_timeout = 0;
+gboolean omp_playback_ui_timeout_halted;
-
-
/**
* Initializes gstreamer by setting up pipe, message hooks and bins
*/
@@ -48,7 +48,9 @@
}
// Create the signals we'll emit
- g_signal_new(OMP_EVENT_PLAYBACK_EOS, G_TYPE_OBJECT, 0, 0, 0, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+ g_signal_new(OMP_EVENT_PLAYBACK_EOS,
G_TYPE_OBJECT, 0, 0, 0, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+ g_signal_new(OMP_EVENT_PLAYBACK_STATUS_CHANGED,
G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0,
NULL);
+ g_signal_new(OMP_EVENT_PLAYBACK_POSITION_CHANGED,
G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0,
NULL);
// Set up gstreamer pipe and bins
omp_gst_playbin = gst_element_factory_make("playbin", "play");
@@ -81,6 +83,7 @@
/**
* Attempts to load a track from an URI
+ * @return TRUE if successful, FALSE if failed
*/
gboolean
omp_playback_load_track_from_uri(gchar *uri)
@@ -91,59 +94,171 @@
omp_playback_init();
}
- // DEBUG
- g_printf("Loading %s\n", uri);
+ #ifdef DEBUG
+ g_printf("Loading track: %s\n", uri);
+ #endif
gst_element_set_state(omp_gst_playbin, GST_STATE_NULL);
g_object_set(G_OBJECT(omp_gst_playbin), "uri", uri, NULL);
gst_element_set_state(omp_gst_playbin, GST_STATE_PAUSED);
+
+ return (gst_element_set_state(omp_gst_playbin, GST_STATE_PAUSED) !=
GST_STATE_CHANGE_FAILURE);
}
/**
+ * This callback gets called at least once per second if a track is playing
+ */
+static gboolean
+omp_playback_ui_timeout_callback(gpointer data)
+{
+ g_signal_emit_by_name(G_OBJECT(omp_main_window),
OMP_EVENT_PLAYBACK_POSITION_CHANGED);
+
+ if (omp_playback_ui_timeout_halted)
+ {
+ // Reset the timeout ID so we can prevent race conditions
+ omp_playback_ui_timeout = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
* Starts playback of the current stream
*/
void
omp_playback_play()
{
- // DEBUG
- g_print("Starting playback\n");
+ #ifdef DEBUG
+ g_print("Starting playback\n");
+ #endif
+ // Set state
gst_element_set_state(omp_gst_playbin, GST_STATE_PLAYING);
+ g_signal_emit_by_name(G_OBJECT(omp_main_window),
OMP_EVENT_PLAYBACK_STATUS_CHANGED);
+
+ // 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
+ omp_playback_ui_timeout_halted = FALSE;
+
+ if (!omp_playback_ui_timeout)
+ {
+ omp_playback_ui_timeout =
g_timeout_add(PLAYBACK_UI_UPDATE_INTERVAL, omp_playback_ui_timeout_callback,
NULL);
+ }
}
/**
+ * Suspends playback of the current stream
+ */
+void
+omp_playback_pause()
+{
+ #ifdef DEBUG
+ g_print("Suspending playback\n");
+ #endif
+
+ // Set state
+ gst_element_set_state(omp_gst_playbin, GST_STATE_PAUSED);
+ g_signal_emit_by_name(G_OBJECT(omp_main_window),
OMP_EVENT_PLAYBACK_STATUS_CHANGED);
+
+ // Stop timer
+ omp_playback_ui_timeout_halted = TRUE;
+}
+
+/**
* Returns the current state the playback engine is in
+ * @todo Don't use system clock, might be out-of-sync with playbin clock?
*/
gint
omp_playback_get_state()
{
GstState state;
- GstSystemClock *system_clock;
+ GstClock *clock;
// Poll state with an immediate timeout
- system_clock = gst_system_clock_obtain();
- gst_element_get_state(GST_OBJECT(omp_gst_playbin), &state, NULL,
gst_clock_get_time(system_clock));
- gst_object_unref(system_clock);
+ clock = gst_system_clock_obtain();
+ gst_element_get_state(GST_ELEMENT(omp_gst_playbin), &state, NULL,
gst_clock_get_time(clock));
+ gst_object_unref(clock);
- // The NULL element state is no different from READY for more abstract
layers
- if (state == GST_STATE_NULL)
+ // The NULL and READY element states are no different from PAUSED for
more abstract layers
+ if ( (state == GST_STATE_NULL) || (state == GST_STATE_READY) )
{
- state = GST_STATE_READY;
+ state = GST_STATE_PAUSED;
}
return (gint)state;
}
/**
+ * Returns the number of seconds that the track has been playing so far
+ */
+gulong
+omp_playback_get_track_position()
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 position;
+
+ if (!omp_gst_playbin)
+ {
+ return 0;
+ }
+
+ // Return 0 if function returns FALSE, position otherwise
+ return (gst_element_query_position(omp_gst_playbin, &format,
&position)) ? (position/GST_SECOND) : 0;
+}
+
+/**
+ * Sets the playback position of the currently loaded track
+ */
+void
+omp_playback_set_track_position(glong position)
+{
+ if (!omp_gst_playbin)
+ {
+ return;
+ }
+
+ gst_element_seek_simple(GST_ELEMENT(omp_gst_playbin),
+ GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+ position*GST_SECOND);
+
+ g_signal_emit_by_name(G_OBJECT(omp_main_window),
OMP_EVENT_PLAYBACK_POSITION_CHANGED);
+}
+
+/**
+ * Returns the current track's playing length
+ */
+gulong
+omp_playback_get_track_length()
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 length;
+
+ if (!omp_gst_playbin)
+ {
+ return 0;
+ }
+
+ // Return 0 if function returns FALSE, track length otherwise
+ return (gst_element_query_duration(omp_gst_playbin, &format, &length))
? (length/GST_SECOND) : 0;
+}
+
+/**
* Handles gstreamer's end-of-stream notification
*/
static gboolean
omp_gst_message_eos(GstBus *bus, GstMessage *message, gpointer data)
{
- // DEBUG
- g_printf("End of stream reached.\n");
+ #ifdef DEBUG
+ g_printf("End of stream reached.\n");
+ #endif
- gst_element_set_state(omp_gst_playbin, GST_STATE_NULL);
+ // Reset playback engine
+ 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);
return TRUE;
@@ -157,9 +272,12 @@
{
GError *error;
- gst_message_parse_error(message, &error, NULL);
- g_printerr("gstreamer error: %s\n", error->message);
- g_error_free(error);
+ #ifdef DEBUG
+ gst_message_parse_error(message, &error, NULL);
+ g_printerr("gstreamer error: %s\n", error->message);
+ gst_message_unref(error);
+ g_error_free(error);
+ #endif
return TRUE;
}
@@ -172,10 +290,12 @@
{
GError *error;
- gst_message_parse_error(message, &error, NULL);
- g_printerr("gstreamer warning: %s\n", error->message);
- g_error_free(error);
+ #ifdef DEBUG
+ gst_message_parse_warning(message, &error, NULL);
+ g_printerr("gstreamer warning: %s\n", error->message);
+ gst_message_unref(error);
+ g_error_free(error);
+ #endif
return TRUE;
}
-
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h
2007-08-04 12:50:34 UTC (rev 2631)
@@ -30,12 +30,15 @@
#include <gst/gst.h>
#define OMP_EVENT_PLAYBACK_EOS "playback_end_of_stream"
+#define OMP_EVENT_PLAYBACK_STATUS_CHANGED "playback_status_change"
+#define OMP_EVENT_PLAYBACK_POSITION_CHANGED "playback_position_change"
// Player states masking the gstreamer states so we can be more abstract
-#define OMP_PLAYBACK_STATE_READY GST_STATE_READY
#define OMP_PLAYBACK_STATE_PAUSED GST_STATE_PAUSED
#define OMP_PLAYBACK_STATE_PLAYING GST_STATE_PLAYING
+// The UI will be updated at this interval when a track is playing (in ms)
+#define PLAYBACK_UI_UPDATE_INTERVAL 1000
void omp_playback_init();
void omp_playback_free();
@@ -43,7 +46,11 @@
gboolean omp_playback_load_track_from_uri(gchar *uri);
void omp_playback_play();
+void omp_playback_pause();
gint omp_playback_get_state();
+gulong omp_playback_get_track_position();
+void omp_playback_set_track_position(glong position);
+gulong omp_playback_get_track_length();
static gboolean omp_gst_message_eos(GstBus *bus, GstMessage *message, gpointer
data);
static gboolean omp_gst_message_error(GstBus *bus, GstMessage *message,
gpointer data);
Modified:
trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c
2007-08-04 12:50:34 UTC (rev 2631)
@@ -62,8 +62,7 @@
g_signal_connect(G_OBJECT(omp_main_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_PREV_TRACK, G_TYPE_OBJECT, 0, 0, 0, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
- g_signal_new(OMP_EVENT_NEXT_TRACK, G_TYPE_OBJECT, 0, 0, 0, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+ 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);
}
/**
@@ -93,6 +92,14 @@
void
omp_playlist_load(gchar *playlist_file)
{
+ // Free the track history's memory by deleting the first element until
the list is empty
+ while (omp_track_history)
+ {
+ g_free(omp_track_history->data);
+ omp_track_history = g_slist_delete_link(omp_track_history,
omp_track_history);
+ }
+
+ // Let XSPF clean up, too
if (omp_playlist)
{
spiff_free(omp_playlist);
@@ -124,8 +131,9 @@
struct spiff_track *track;
gint track_num = 0;
- // DEBUG
- g_printf("Setting current track to #%d\n", playlist_pos);
+ #ifdef DEBUG
+ g_printf("Setting current track to #%d\n", playlist_pos);
+ #endif
if (!omp_playlist)
{
@@ -146,6 +154,9 @@
if (position_valid)
{
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);
}
return position_valid;
@@ -161,6 +172,7 @@
{
struct omp_track_history_entry *history_entry;
struct spiff_track *track;
+ gboolean was_playing;
gboolean is_new_track = FALSE;
if (!omp_playlist_current_track)
@@ -168,6 +180,34 @@
return;
}
+ // If track playing time is >= 10 seconds we just jump back to the
beginning of the track
+ if (omp_playback_get_track_position() >= 10)
+ {
+ omp_playback_set_track_position(0);
+ return TRUE;
+ }
+
+ // Get player state so we can continue playback if necessary
+ was_playing = (omp_playback_get_state() == OMP_PLAYBACK_STATE_PLAYING);
+
+try_again:
+
+ #ifdef DEBUG
+ if (omp_track_history)
+ {
+ GSList *list;
+ g_printf("--- Track History:\n");
+ list = omp_track_history;
+ while (list)
+ {
+ history_entry = list->data;
+ g_printf("- %s\n",
history_entry->track->locations->value);
+ list = g_slist_next(list);
+ }
+ g_printf("---\n");
+ }
+ #endif
+
// Do we have tracks in the history to go back to?
if (omp_track_history)
{
@@ -197,7 +237,7 @@
// We only found the previous track if we're not at the
end of the list
if (track->next)
{
- omp_playlist_current_track = track;
+ omp_playlist_current_track = track;
omp_playlist_current_track_id--;
}
}
@@ -206,7 +246,19 @@
if (is_new_track)
{
// Emit signal to update UI and the like
- g_signal_emit_by_name(G_OBJECT(omp_main_window),
OMP_EVENT_PREV_TRACK);
+ g_signal_emit_by_name(G_OBJECT(omp_main_window),
OMP_EVENT_PLAYLIST_TRACK_CHANGED);
+
+ // Load track and start playing if needed
+ if (omp_playlist_load_current_track())
+ {
+ if (was_playing) omp_playback_play();
+
+ } else {
+
+ // Uh-oh, track failed to load - let's find another
one, shall we?
+ is_new_track = FALSE;
+ goto try_again;
+ }
}
return is_new_track;
@@ -237,8 +289,8 @@
// Prepare the history entry - if we don't need it we'll just free it
again
history_entry = g_new(struct omp_track_history_entry, 1);
- history_entry->track = omp_playlist_current_track;
- history_entry->track_id = omp_playlist_current_track_id;
+ history_entry->track = omp_playlist_current_track;
+ history_entry->track_id = omp_playlist_current_track_id;
// Do we have a track to play?
if (omp_playlist_current_track->next)
@@ -256,7 +308,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_NEXT_TRACK);
+ g_signal_emit_by_name(G_OBJECT(omp_main_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-mediaplayer/src/playlist.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h
2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h
2007-08-04 12:50:34 UTC (rev 2631)
@@ -29,13 +29,8 @@
#include <spiff/spiff_c.h>
-#define OMP_EVENT_PREV_TRACK "prev_track"
-#define OMP_EVENT_NEXT_TRACK "next_track"
+#define OMP_EVENT_PLAYLIST_TRACK_CHANGED "playlist_track_changed"
-
-extern struct _omp_playlist_events omp_playlist_events;
-
-
extern struct spiff_list *omp_playlist;
extern guint omp_playlist_track_count;
--- End Message ---