changeset 780:985d000c343c trunk

[svn] - aosd: experimental single-threaded osd; now the osd works in the same thread of the player, thus issues related to cairo and pango hopefully should go away; further testing on different system is required
author giacomo
date Sun, 04 Mar 2007 16:45:52 -0800
parents 5f53309bb7d8
children 87bd9a74ca4f
files ChangeLog src/aosd/aosd_osd.c
diffstat 2 files changed, 241 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Mar 04 01:50:27 2007 -0800
+++ b/ChangeLog	Sun Mar 04 16:45:52 2007 -0800
@@ -1,3 +1,11 @@
+2007-03-04 09:50:27 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
+  revision [1656]
+  - fix for missing ordinals, closes #830.
+  
+  trunk/src/flac/plugin_common/Makefile |    2 +-
+  1 file changed, 1 insertion(+), 1 deletion(-)
+
+
 2007-03-04 06:55:57 +0000  Yoshiki Yazawa <yaz@cc.rim.or.jp>
   revision [1654]
   - hide seek bar for unseekable (info->size = 0) stream.
--- a/src/aosd/aosd_osd.c	Sun Mar 04 01:50:27 2007 -0800
+++ b/src/aosd/aosd_osd.c	Sun Mar 04 16:45:52 2007 -0800
@@ -33,30 +33,20 @@
 #include "ghosd.h"
 
 
-#define AOSD_STATUS_HIDDEN    0
-#define AOSD_STATUS_SHOWN     1
-#define AOSD_STATUS_INTERRUPT 2
-
-
-static pthread_t * aosd_thread = NULL;
-static pthread_mutex_t aosd_status_mutex = PTHREAD_MUTEX_INITIALIZER;
-static gboolean aosd_status = AOSD_STATUS_HIDDEN;
-
-
-typedef struct
-{
-  gchar * markup_message;
-  aosd_cfg_osd_t * cfg_osd;
-  gboolean cfg_is_copied;
-}
-aosd_thread_data_t;
+#define AOSD_STATUS_HIDDEN       0
+#define AOSD_STATUS_FADEIN       1
+#define AOSD_STATUS_SHOW         2
+#define AOSD_STATUS_FADEOUT      3
+#define AOSD_STATUS_DESTROY      4
+/* updating OSD every 50 msec */
+#define AOSD_TIMING              50
 
 
 typedef struct
 {
   cairo_surface_t * surface;
-  float alpha;
-  void * user_data;
+  gfloat alpha;
+  gpointer user_data;
   gint width;
   gint height;
   gint deco_code;
@@ -64,8 +54,100 @@
 GhosdFadeData;
 
 
+typedef struct
+{
+  gchar * markup_message;
+  gboolean cfg_is_copied;
+  gfloat dalpha_in, dalpha_out, ddisplay_stay;
+
+  PangoContext *pango_context;
+  PangoLayout *pango_layout;
+
+  aosd_cfg_osd_t * cfg_osd;
+
+  GhosdFadeData fade_data;
+}
+GhosdData;
+
+
+static gint osd_source_id = 0;
+static gint osd_status = AOSD_STATUS_HIDDEN;
+static Ghosd *osd;
+static GhosdData *osd_data;
+
+
 static void
-aosd_fade_func ( Ghosd * osd , cairo_t * cr , void * user_data )
+aosd_osd_data_alloc ( gchar * markup_string , aosd_cfg_osd_t * cfg_osd , gboolean copy_cfg )
+{
+  osd_data = g_malloc0(sizeof(GhosdData));
+  osd_data->markup_message = g_strdup( markup_string );
+  if ( copy_cfg == TRUE )
+  {
+    osd_data->cfg_osd = aosd_cfg_osd_copy( cfg_osd );
+    osd_data->cfg_is_copied = TRUE;
+  }
+  else
+  {
+    osd_data->cfg_osd = cfg_osd;
+    osd_data->cfg_is_copied = FALSE;
+  }
+  return;
+}
+
+
+static void
+aosd_osd_data_free ( void )
+{
+  if ( osd_data->fade_data.surface != NULL )
+  {
+    cairo_surface_destroy( osd_data->fade_data.surface );
+    osd_data->fade_data.surface = NULL;
+  }
+
+  if ( osd_data->markup_message != NULL )
+  {
+    g_free( osd_data->markup_message );
+    osd_data->markup_message = NULL;
+  }
+
+  if ( osd_data->cfg_is_copied == TRUE )
+  {
+    aosd_cfg_osd_delete( osd_data->cfg_osd );
+    osd_data->cfg_osd = NULL;
+  }
+
+  if ( osd_data->pango_layout != NULL )
+  {
+    g_object_unref( osd_data->pango_layout );
+    osd_data->pango_layout = NULL;
+  }
+
+  if ( osd_data->pango_context != NULL )
+  {
+    g_object_unref( osd_data->pango_context );
+    osd_data->pango_context = NULL;
+  }
+
+  g_free( osd_data );
+}
+
+
+static void
+aosd_osd_hideanddestroy ( void )
+{
+  if ( osd != NULL )
+  {
+    ghosd_hide( osd );
+    ghosd_main_iterations( osd );
+    ghosd_destroy( osd );
+    osd = NULL;
+  }
+  return;
+}
+
+
+static void
+aosd_fade_func ( Ghosd * gosd , cairo_t * cr , void * user_data )
 {
   GhosdFadeData *fade_data = user_data;
 
@@ -75,7 +157,7 @@
     fade_data->surface = cairo_surface_create_similar( cairo_get_target( cr ) ,
                            CAIRO_CONTENT_COLOR_ALPHA , fade_data->width , fade_data->height );
     rendered_cr = cairo_create( fade_data->surface );
-    aosd_deco_style_render( fade_data->deco_code , osd , rendered_cr , fade_data->user_data );
+    aosd_deco_style_render( fade_data->deco_code , gosd , rendered_cr , fade_data->user_data );
     cairo_destroy( rendered_cr );
   }
 
@@ -85,46 +167,32 @@
 
 
 static void
-aosd_button_func ( Ghosd * osd , GhosdEventButton * ev , void * user_data )
+aosd_button_func ( Ghosd * gosd , GhosdEventButton * ev , void * user_data )
 {
   if ( ev->button == 1 )
   {
-    pthread_mutex_lock( &aosd_status_mutex );
-    aosd_status = AOSD_STATUS_INTERRUPT;
-    pthread_mutex_unlock( &aosd_status_mutex );
+    osd_status = AOSD_STATUS_DESTROY; /* move to status destroy */
   }
   return;
 }
 
 
-static void *
-aosd_thread_func ( void * arg )
+static void
+aosd_osd_create ( void )
 {
-  aosd_thread_data_t *thread_data = (aosd_thread_data_t*)arg;
-  gchar *markup_string = thread_data->markup_message;
-  aosd_cfg_osd_t *cfg_osd = thread_data->cfg_osd;
-  Ghosd *osd;
-  GhosdFadeData fade_data = { NULL , 0 , NULL , 0 , 0 , 0 };
-  PangoContext *context;
-  PangoLayout *osd_layout;
   gint max_width, layout_width, layout_height;
+  GdkScreen *screen = gdk_screen_get_default();
   gint pos_x = 0, pos_y = 0;
   gint pad_left = 0 , pad_right = 0 , pad_top = 0 , pad_bottom = 0;
   gint screen_width, screen_height;
-  const gint STEP_MS = 50;
-  const gfloat dalpha_in = 1.0 / ( cfg_osd->animation.timing_fadein / (gfloat)STEP_MS );
-  const gfloat dalpha_out = 1.0 / ( cfg_osd->animation.timing_fadeout / (gfloat)STEP_MS );
-  struct timeval tv_nextupdate;
-  gboolean stop_now = FALSE;
   aosd_deco_style_data_t style_data;
-  GdkScreen *screen = gdk_screen_get_default();
 
   /* calculate screen_width and screen_height */
-  if ( cfg_osd->position.multimon_id > -1 )
+  if ( osd_data->cfg_osd->position.multimon_id > -1 )
   {
     /* adjust coordinates and size according to selected monitor */
     GdkRectangle rect;
-    gdk_screen_get_monitor_geometry( screen , cfg_osd->position.multimon_id , &rect );
+    gdk_screen_get_monitor_geometry( screen , osd_data->cfg_osd->position.multimon_id , &rect );
     pos_x = rect.x;
     pos_y = rect.y;
     screen_width = rect.width;
@@ -140,34 +208,34 @@
   }
 
   /* pick padding from selected decoration style */
-  aosd_deco_style_get_padding( cfg_osd->decoration.code ,
+  aosd_deco_style_get_padding( osd_data->cfg_osd->decoration.code ,
     &pad_top , &pad_bottom , &pad_left , &pad_right );
 
-  if ( cfg_osd->position.maxsize_width > 0 )
+  if ( osd_data->cfg_osd->position.maxsize_width > 0 )
   {
-    gint max_width_default = screen_width - pad_left - pad_right - abs(cfg_osd->position.offset_x);
-    max_width = cfg_osd->position.maxsize_width - pad_left - pad_right;
+    gint max_width_default = screen_width - pad_left - pad_right - abs(osd_data->cfg_osd->position.offset_x);
+    max_width = osd_data->cfg_osd->position.maxsize_width - pad_left - pad_right;
     /* ignore user-defined max_width if it is too small or too large */
     if (( max_width < 1 ) || ( max_width > max_width_default ))
       max_width = max_width_default;
   }
   else
   {
-    max_width = screen_width - pad_left - pad_right - abs(cfg_osd->position.offset_x);
+    max_width = screen_width - pad_left - pad_right - abs(osd_data->cfg_osd->position.offset_x);
   }
-  context = pango_cairo_font_map_create_context(
-              PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default()));
-  osd_layout = pango_layout_new(context);
-  pango_layout_set_markup( osd_layout, markup_string , -1 );
-  pango_layout_set_ellipsize( osd_layout , PANGO_ELLIPSIZE_NONE );
-  pango_layout_set_justify( osd_layout , FALSE );
-  pango_layout_set_width( osd_layout , PANGO_SCALE * max_width );
-  pango_layout_get_pixel_size( osd_layout , &layout_width , &layout_height );
+  osd_data->pango_context = pango_cairo_font_map_create_context(
+                              PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default()));
+  osd_data->pango_layout = pango_layout_new(osd_data->pango_context);
+  pango_layout_set_markup( osd_data->pango_layout, osd_data->markup_message , -1 );
+  pango_layout_set_ellipsize( osd_data->pango_layout , PANGO_ELLIPSIZE_NONE );
+  pango_layout_set_justify( osd_data->pango_layout , FALSE );
+  pango_layout_set_width( osd_data->pango_layout , PANGO_SCALE * max_width );
+  pango_layout_get_pixel_size( osd_data->pango_layout , &layout_width , &layout_height );
 
   osd = ghosd_new();
 
   /* osd position */
-  switch ( cfg_osd->position.placement )
+  switch ( osd_data->cfg_osd->position.placement )
   {
     case AOSD_POSITION_PLACEMENT_TOP:
       pos_x += (screen_width - (layout_width + pad_left + pad_right)) / 2;
@@ -209,150 +277,136 @@
   }
 
   /* add offset to position */
-  pos_x += cfg_osd->position.offset_x;
-  pos_y += cfg_osd->position.offset_y;
+  pos_x += osd_data->cfg_osd->position.offset_x;
+  pos_y += osd_data->cfg_osd->position.offset_y;
 
   ghosd_set_position( osd , pos_x , pos_y ,
     layout_width + pad_left + pad_right ,
     layout_height + pad_top + pad_bottom );
 
-  ghosd_set_event_button_cb( osd , aosd_button_func , &stop_now );
-
-  /* the aosd_status must be checked during the fade and display process
-     (if another message arrives, the current transition must be abandoned ) */
+  ghosd_set_event_button_cb( osd , aosd_button_func , NULL );
 
-  style_data.layout = osd_layout;
-  style_data.text = &(cfg_osd->text);
-  style_data.decoration = &(cfg_osd->decoration);
-  fade_data.user_data = &style_data;
-  fade_data.width = layout_width + pad_left + pad_right;
-  fade_data.height = layout_height + pad_top + pad_bottom;
-  fade_data.alpha = 0;
-  fade_data.deco_code = cfg_osd->decoration.code;
-  ghosd_set_render( osd , (GhosdRenderFunc)aosd_fade_func , &fade_data , NULL );
+  style_data.layout = osd_data->pango_layout;
+  style_data.text = &(osd_data->cfg_osd->text);
+  style_data.decoration = &(osd_data->cfg_osd->decoration);
+  osd_data->fade_data.surface = NULL;
+  osd_data->fade_data.user_data = &style_data;
+  osd_data->fade_data.width = layout_width + pad_left + pad_right;
+  osd_data->fade_data.height = layout_height + pad_top + pad_bottom;
+  osd_data->fade_data.alpha = 0;
+  osd_data->fade_data.deco_code = osd_data->cfg_osd->decoration.code;
+  osd_data->dalpha_in = 1.0 / ( osd_data->cfg_osd->animation.timing_fadein / (gfloat)AOSD_TIMING );
+  osd_data->dalpha_out = 1.0 / ( osd_data->cfg_osd->animation.timing_fadeout / (gfloat)AOSD_TIMING );
+  osd_data->ddisplay_stay = 1.0 / ( osd_data->cfg_osd->animation.timing_display / (gfloat)AOSD_TIMING );
+  ghosd_set_render( osd , (GhosdRenderFunc)aosd_fade_func , &(osd_data->fade_data) , NULL );
 
   /* show the osd (with alpha 0, invisible) */
   ghosd_show( osd );
+  return;
+}
 
-  if ( stop_now != TRUE )
+
+static gboolean
+aosd_timer_func ( gpointer none )
+{
+  static gfloat display_time = 0;
+
+  switch ( osd_status )
   {
-    /* fade in */
-    for ( fade_data.alpha = 0 ; fade_data.alpha < 1.0 ; fade_data.alpha += dalpha_in )
+    case AOSD_STATUS_FADEIN:
+    {
+      /* fade in */
+      osd_data->fade_data.alpha += osd_data->dalpha_in;
+      if ( osd_data->fade_data.alpha < 1.0 )
+      {
+        ghosd_render( osd );
+        ghosd_main_iterations( osd );
+      }
+      else
+      {
+        osd_data->fade_data.alpha = 1.0;
+        display_time = 0;
+        osd_status = AOSD_STATUS_SHOW; /* move to next phase */
+        ghosd_render( osd );
+        ghosd_main_iterations( osd );
+      }
+      return TRUE;
+    }
+
+    case AOSD_STATUS_SHOW:
     {
-      pthread_mutex_lock( &aosd_status_mutex );
-      if ( aosd_status == AOSD_STATUS_INTERRUPT )
-        { pthread_mutex_unlock( &aosd_status_mutex ); stop_now = TRUE; break; }
-      pthread_mutex_unlock( &aosd_status_mutex );
+      display_time += osd_data->ddisplay_stay;
+      if ( display_time >= 1.0 )
+      {
+        osd_status = AOSD_STATUS_FADEOUT; /* move to next phase */
+        ghosd_main_iterations( osd );
+      }
+      else
+      {
+        ghosd_main_iterations( osd );
+      }
+      return TRUE;
+    }
 
-      if (fade_data.alpha > 1.0) fade_data.alpha = 1.0;
-      ghosd_render( osd );
-      gettimeofday( &tv_nextupdate , NULL );
-      tv_nextupdate.tv_usec += STEP_MS*1000;
-      ghosd_main_until( osd , &tv_nextupdate );
+    case AOSD_STATUS_FADEOUT:
+    {
+      /* fade out */
+      osd_data->fade_data.alpha -= osd_data->dalpha_out;
+      if ( osd_data->fade_data.alpha > 0.0 )
+      {
+        ghosd_render( osd );
+        ghosd_main_iterations( osd );
+      }
+      else
+      {
+        osd_data->fade_data.alpha = 0.0;
+        osd_status = AOSD_STATUS_DESTROY; /* move to next phase */
+        ghosd_render( osd );
+        ghosd_main_iterations( osd );
+      }
+      return TRUE;
+    }
+
+    case AOSD_STATUS_DESTROY:
+    {
+      aosd_osd_hideanddestroy();
+      aosd_osd_data_free();
+
+      osd_status = AOSD_STATUS_HIDDEN; /* reset status */
+      osd_source_id = 0;
+      return FALSE;
     }
   }
 
-  if ( stop_now != TRUE )
-  {
-    /* show the osd for the desidered amount of time */
-    gint time_iter_ms = 0;
-
-    fade_data.alpha = 1.0;
-    ghosd_render( osd );
-
-    while ( time_iter_ms < cfg_osd->animation.timing_display )
-    {
-      pthread_mutex_lock( &aosd_status_mutex );
-      if ( aosd_status == AOSD_STATUS_INTERRUPT )
-        { pthread_mutex_unlock( &aosd_status_mutex ); stop_now = TRUE; break; }
-      pthread_mutex_unlock( &aosd_status_mutex );
-
-      gettimeofday(&tv_nextupdate, NULL);
-      tv_nextupdate.tv_usec += STEP_MS*1000;
-      time_iter_ms += STEP_MS;
-      ghosd_main_until( osd , &tv_nextupdate);
-    }
-  }
-
-  if ( stop_now != TRUE )
-  {
-    /* fade out */
-    for ( fade_data.alpha = 1 ; fade_data.alpha > 0.0 ; fade_data.alpha -= dalpha_out )
-    {
-      pthread_mutex_lock( &aosd_status_mutex );
-      if ( aosd_status == AOSD_STATUS_INTERRUPT )
-        { pthread_mutex_unlock( &aosd_status_mutex ); stop_now = TRUE; break; }
-      pthread_mutex_unlock( &aosd_status_mutex );
-
-      if (fade_data.alpha < 0.0) fade_data.alpha = 0;
-      ghosd_render( osd );
-      gettimeofday( &tv_nextupdate , NULL );
-      tv_nextupdate.tv_usec += STEP_MS*1000;
-      ghosd_main_until( osd , &tv_nextupdate );
-    }
-  }
-
-  fade_data.alpha = 0;
-  ghosd_render( osd );
-
-  ghosd_hide( osd );
-  ghosd_main_iterations( osd );
-  ghosd_destroy( osd );
-  if ( fade_data.surface != NULL )
-    cairo_surface_destroy( fade_data.surface );
-
-  pthread_mutex_lock( &aosd_status_mutex );
-  aosd_status = AOSD_STATUS_HIDDEN;
-  pthread_mutex_unlock( &aosd_status_mutex );
-
-  g_free( markup_string );
-  if ( thread_data->cfg_is_copied == TRUE )
-    aosd_cfg_osd_delete( cfg_osd );
-  g_free( thread_data );
-  g_object_unref( osd_layout );
-  g_object_unref( context );
-  pthread_exit(NULL);
+  return TRUE;
 }
 
 
 gint
 aosd_display ( gchar * markup_string , aosd_cfg_osd_t * cfg_osd , gboolean copy_cfg )
 {
-  aosd_thread_data_t *thread_data = g_malloc(sizeof(aosd_thread_data_t));
-  thread_data->markup_message = g_strdup( markup_string );
-  if ( copy_cfg == TRUE )
+  if ( osd_status == AOSD_STATUS_HIDDEN )
   {
-    thread_data->cfg_osd = aosd_cfg_osd_copy( cfg_osd );
-    thread_data->cfg_is_copied = TRUE;
+    aosd_osd_data_alloc( markup_string , cfg_osd , copy_cfg );
+    aosd_osd_create();
+    osd_status = AOSD_STATUS_FADEIN;
+    osd_source_id = g_timeout_add_full( G_PRIORITY_DEFAULT_IDLE , AOSD_TIMING ,
+                                        aosd_timer_func , NULL , NULL );
   }
   else
   {
-    thread_data->cfg_osd = cfg_osd;
-    thread_data->cfg_is_copied = FALSE;
-  }
-
-  /* check if osd is already displaying a message now */
-  pthread_mutex_lock( &aosd_status_mutex );
-  if ( aosd_status == AOSD_STATUS_SHOWN )
-  {
-    /* a message is already being shown in osd, stop the
-       display of that message cause there is a new one */
-    aosd_status = AOSD_STATUS_INTERRUPT;
+    g_source_remove( osd_source_id ); /* remove timer */
+    osd_source_id = 0;
+    aosd_osd_hideanddestroy();
+    aosd_osd_data_free();
+    osd_status = AOSD_STATUS_HIDDEN;
+    /* now display new OSD */
+    aosd_osd_data_alloc( markup_string , cfg_osd , copy_cfg );
+    aosd_osd_create();
+    osd_status = AOSD_STATUS_FADEIN;
+    osd_source_id = g_timeout_add_full( G_PRIORITY_DEFAULT_IDLE , AOSD_TIMING ,
+                                        aosd_timer_func , NULL , NULL );
   }
-  else
-  {
-    /* no message is being shown in osd, show one now */
-    aosd_status = AOSD_STATUS_SHOWN;
-  }
-  pthread_mutex_unlock( &aosd_status_mutex );
-
-  if ( aosd_thread != NULL )
-    pthread_join( *aosd_thread , NULL );
-  else
-    aosd_thread = g_malloc(sizeof(pthread_t));
-
-  aosd_status = AOSD_STATUS_SHOWN; /* aosd_thread joined, no need to mutex this */
-  pthread_create( aosd_thread , NULL , aosd_thread_func , thread_data );
   return 0;
 }
 
@@ -360,20 +414,13 @@
 void
 aosd_shutdown ( void )
 {
-  if ( aosd_thread != NULL )
+  if ( osd_status != AOSD_STATUS_HIDDEN ) /* osd is being displayed */
   {
-    pthread_mutex_lock( &aosd_status_mutex );
-    if ( aosd_status == AOSD_STATUS_SHOWN )
-    {
-      /* a message is being shown in osd,
-         stop the display of that message */
-      aosd_status = AOSD_STATUS_INTERRUPT;
-    }
-    pthread_mutex_unlock( &aosd_status_mutex );
-    pthread_join( *aosd_thread , NULL );
-    g_free( aosd_thread );
-    aosd_thread = NULL;
-    aosd_status = AOSD_STATUS_HIDDEN; /* aosd_thread joined, no need to mutex this */
+    g_source_remove( osd_source_id ); /* remove timer */
+    osd_source_id = 0;
+    aosd_osd_hideanddestroy();
+    aosd_osd_data_free();
+    osd_status = AOSD_STATUS_HIDDEN;
   }
   return;
 }