Mercurial > audlegacy-plugins
changeset 569:d401f87f89f7 trunk
[svn] - added Audacious OSD, yet-another-written-from-scratch plugin to display OSD, based on Ghosd library; currently untied from configure, to compile it you have to run make in its directory; will be added to configure after some testing
author | giacomo |
---|---|
date | Mon, 29 Jan 2007 06:40:04 -0800 |
parents | 8c64b5abdcda |
children | 9774ac406bde |
files | ChangeLog src/aosd/Makefile src/aosd/aosd.c src/aosd/aosd.h src/aosd/aosd_cfg.c src/aosd/aosd_cfg.h src/aosd/aosd_common.h src/aosd/aosd_osd.c src/aosd/aosd_osd.h src/aosd/aosd_style.c src/aosd/aosd_style.h src/aosd/aosd_style_private.h src/aosd/aosd_ui.c src/aosd/aosd_ui.c.old src/aosd/aosd_ui.h src/aosd/ghosd-internal.h src/aosd/ghosd-license src/aosd/ghosd-main.c src/aosd/ghosd-text.c src/aosd/ghosd-text.h src/aosd/ghosd.c src/aosd/ghosd.h |
diffstat | 22 files changed, 3202 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Mon Jan 29 03:34:57 2007 -0800 +++ b/ChangeLog Mon Jan 29 06:40:04 2007 -0800 @@ -1,3 +1,11 @@ +2007-01-29 11:34:57 +0000 William Pitcock <nenolod@sacredspiral.co.uk> + revision [1222] + - fix seek() routine for InputPlayback API. + + trunk/src/tta/aud-tta.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + 2007-01-29 11:33:15 +0000 William Pitcock <nenolod@sacredspiral.co.uk> revision [1220] - update to new plugin API
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/Makefile Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,18 @@ +include ../../mk/rules.mk +include ../../mk/init.mk + +OBJECTIVE_LIBS = libaosd$(SHARED_SUFFIX) + +noinst_HEADERS = aosd.h aosd_osd.h aosd_style.h aosd_ui.h aosd_cfg.h aosd_common.h ghosd.h ghosd-text.h ghosd-internal.h + +LIBDIR = $(plugindir)/$(GENERAL_PLUGIN_DIR) + +LIBADD = $(GTK_LIBS) +SOURCES = aosd.c aosd_osd.c aosd_style.c aosd_ui.c aosd_cfg.c ghosd.c ghosd-text.c ghosd-main.c + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) \ + -I../../intl -I../.. -I.. + +include ../../mk/objective.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,140 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#include "aosd.h" +#include "aosd_osd.h" +#include "aosd_cfg.h" +#include <audacious/input.h> +#include <audacious/playlist.h> +#include <audacious/strings.h> + + +static guint timeout_sid = 0; +static gchar *prev_title = NULL; +static gboolean was_playing = FALSE; +aosd_cfg_t * global_config = NULL; + + +gboolean +aosd_check_pl_change ( gpointer data ) +{ + if ( ip_data.playing ) + { + Playlist *active = playlist_get_active(); + gint pos = playlist_get_position(active); + gchar *title = playlist_get_songtitle(active, pos); + + if ( ( title != NULL ) && + ( (( prev_title != NULL ) && ( strcmp(title,prev_title) )) || + ( was_playing == FALSE ) ) ) + { + /* string formatting is done here a.t.m. - TODO - improve this area */ + gchar *utf8_title = str_to_utf8( title ); + gchar *utf8_title_markup = g_markup_printf_escaped( + "<span font_desc='%s'>%s</span>" , global_config->osd->text.fonts_name[0] , utf8_title ); + aosd_display( utf8_title_markup , global_config->osd , FALSE ); + g_free( utf8_title_markup ); + g_free( utf8_title ); + } + + if ( prev_title != NULL ) + g_free(prev_title); + prev_title = g_strdup(title); + + g_free( title ); + } + else + { + if ( prev_title != NULL ) + { g_free(prev_title); prev_title = NULL; } + } + + was_playing = ip_data.playing; + return TRUE; +} + + +/* ***************** */ +/* plug-in functions */ + +GeneralPlugin *get_gplugin_info() +{ + return &aosd_gp; +} + + +void +aosd_init ( void ) +{ + g_log_set_handler( NULL , G_LOG_LEVEL_WARNING , g_log_default_handler , NULL ); + + global_config = aosd_cfg_new(); + aosd_cfg_load( global_config ); + + timeout_sid = g_timeout_add( 500 , (GSourceFunc)aosd_check_pl_change , NULL ); + return; +} + + +void +aosd_cleanup ( void ) +{ + if ( timeout_sid > 0 ) + g_source_remove( timeout_sid ); + + if ( prev_title != NULL ) + { + g_free(prev_title); + prev_title = NULL; + } + + aosd_shutdown(); + + if ( global_config != NULL ) + { + aosd_cfg_delete( global_config ); + global_config = NULL; + } + + return; +} + + +void +aosd_configure ( void ) +{ + /* create a new configuration object */ + aosd_cfg_t *cfg = aosd_cfg_new(); + /* fill it with information from config file */ + aosd_cfg_load( cfg ); + /* call the configuration UI */ + aosd_ui_configure( cfg ); + /* delete configuration object */ + aosd_cfg_delete( cfg ); + return; +} + + +void +aosd_about ( void ) +{ + aosd_ui_about(); + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,45 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_H +#define _I_AOSD_H 1 + +#include "aosd_common.h" +#include <glib.h> +#include <audacious/plugin.h> + +void aosd_init ( void ); +void aosd_cleanup ( void ); +void aosd_configure ( void ); +void aosd_about ( void ); + +GeneralPlugin aosd_gp = +{ + NULL, /* handle */ + NULL, /* filename */ + -1, /* session */ + "Audacious OSD " AOSD_VERSION_PLUGIN, /* description */ + aosd_init, /* init */ + aosd_about, /* about */ + aosd_configure, /* configure */ + aosd_cleanup /* cleanup */ +}; + +#endif /* !_I_AOSD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_cfg.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,386 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#include "aosd_cfg.h" +#include "aosd_style.h" +#include <glib.h> +#include <stdlib.h> +#include <audacious/configdb.h> + + +static gint +aosd_cfg_util_str_to_color ( gchar * str , aosd_color_t * color ) +{ + /* color strings are in format "x,x,x,x", where x are numbers + that represent respectively red, green, blue and alpha values (0-65535) */ + gchar **str_values = g_strsplit( str , "," , 4 ); + gint col_values[4] = { 0 , 0 , 0, 65535 }; + gint i = 0; + while ( str_values[i] != NULL ) + { + col_values[i] = (gint)strtol( str_values[i] , NULL , 10 ); + i++; + } + g_strfreev( str_values ); + color->red = col_values[0]; + color->green = col_values[1]; + color->blue = col_values[2]; + color->alpha = col_values[3]; + if ( i < 4 ) + return -1; + else + return 0; +} + + +static gint +aosd_cfg_util_color_to_str ( aosd_color_t color , gchar ** str ) +{ + /* color strings are in format "x,x,x,x", where x are numbers + that represent respectively red, green, blue and alpha values (0-65535) */ + *str = g_strdup_printf( "%i,%i,%i,%i" , color.red , color.green , color.blue , color.alpha ); + if ( *str != NULL ) + return 0; + else + return -1; +} + + +aosd_cfg_t * +aosd_cfg_new ( void ) +{ + aosd_cfg_t *cfg = g_malloc0(sizeof(aosd_cfg_t)); + aosd_cfg_osd_t *cfg_osd = aosd_cfg_osd_new(); + cfg->set = FALSE; + cfg->osd = cfg_osd; + return cfg; +} + + +void +aosd_cfg_delete ( aosd_cfg_t * cfg ) +{ + if ( cfg != NULL ) + { + if ( cfg->osd != NULL ) + aosd_cfg_osd_delete( cfg->osd ); + g_free( cfg ); + } + return; +} + + +aosd_cfg_osd_t * +aosd_cfg_osd_new( void ) +{ + aosd_cfg_osd_t *cfg_osd = g_malloc0(sizeof(aosd_cfg_osd_t)); + cfg_osd->decoration.colors = g_array_sized_new( FALSE , TRUE , sizeof(aosd_color_t) , + aosd_deco_style_get_max_numcol() ); + return cfg_osd; +} + + +void +aosd_cfg_osd_delete ( aosd_cfg_osd_t * cfg_osd ) +{ + if ( cfg_osd != NULL ) + { + gint i = 0; + /* free configuration fields */ + for ( i = 0 ; i < AOSD_TEXT_FONTS_NUM ; i++ ) + { + if ( cfg_osd->text.fonts_name[i] != NULL ) + g_free( cfg_osd->text.fonts_name[i] ); + } + if ( cfg_osd->decoration.skin_file != NULL ) + g_free( cfg_osd->decoration.skin_file ); + if ( cfg_osd->decoration.colors != NULL ) + g_array_free( cfg_osd->decoration.colors , TRUE ); + } + g_free( cfg_osd ); + return; +} + + +/* makes a copy of a aosd_cfg_osd_t object (mostly used by aosd_display) */ +aosd_cfg_osd_t * +aosd_cfg_osd_copy ( aosd_cfg_osd_t * cfg_osd ) +{ + aosd_cfg_osd_t *cfg_osd_copy = aosd_cfg_osd_new(); + gint i = 0; + /* copy information */ + cfg_osd_copy->position.placement = cfg_osd->position.placement; + cfg_osd_copy->position.offset_x = cfg_osd->position.offset_x; + cfg_osd_copy->position.offset_y = cfg_osd->position.offset_y; + cfg_osd_copy->animation.timing_display = cfg_osd->animation.timing_display; + cfg_osd_copy->animation.timing_fadein = cfg_osd->animation.timing_fadein; + cfg_osd_copy->animation.timing_fadeout = cfg_osd->animation.timing_fadeout; + for ( i = 0 ; i < AOSD_TEXT_FONTS_NUM ; i++ ) + { + cfg_osd_copy->text.fonts_name[i] = g_strdup( cfg_osd->text.fonts_name[i] ); + cfg_osd_copy->text.fonts_color[i] = cfg_osd->text.fonts_color[i]; + cfg_osd_copy->text.fonts_draw_shadow[i] = cfg_osd->text.fonts_draw_shadow[i]; + cfg_osd_copy->text.fonts_shadow_color[i] = cfg_osd->text.fonts_shadow_color[i]; + } + cfg_osd_copy->decoration.code = cfg_osd->decoration.code; + cfg_osd_copy->decoration.skin_file = g_strdup( cfg_osd->decoration.skin_file ); + for ( i = 0 ; i < cfg_osd->decoration.colors->len ; i++ ) + { + aosd_color_t color = g_array_index( cfg_osd->decoration.colors , aosd_color_t , i ); + g_array_insert_val( cfg_osd_copy->decoration.colors , i , color ); + } + return cfg_osd_copy; +} + + +#ifdef DEBUG +void +aosd_cfg_debug ( aosd_cfg_t * cfg ) +{ + gint i = 0; + g_print("\n***** debug configuration *****\n\n"); + g_print("POSITION\n"); + g_print(" placement: %i\n", cfg->osd->position.placement); + g_print(" offset x: %i\n", cfg->osd->position.offset_x); + g_print(" offset y: %i\n", cfg->osd->position.offset_y); + g_print("\nANIMATION\n"); + g_print(" timing display: %i\n", cfg->osd->animation.timing_display); + g_print(" timing fade in: %i\n", cfg->osd->animation.timing_fadein); + g_print(" timing fade out: %i\n", cfg->osd->animation.timing_fadeout); + g_print("\nTEXT\n"); + for ( i = 0 ; i < AOSD_TEXT_FONTS_NUM ; i++ ) + { + g_print(" font %i: %s\n", i, cfg->osd->text.fonts_name[i]); + g_print(" font color %i: %i,%i,%i (alpha %i)\n", i, + cfg->osd->text.fonts_color[i].red, cfg->osd->text.fonts_color[i].green, + cfg->osd->text.fonts_color[i].blue, cfg->osd->text.fonts_color[i].alpha); + g_print(" font %i use shadow: %i\n", i, cfg->osd->text.fonts_draw_shadow[i]); + g_print(" font %i shadow color: %i,%i,%i (alpha %i)\n", i, + cfg->osd->text.fonts_shadow_color[i].red, cfg->osd->text.fonts_shadow_color[i].green, + cfg->osd->text.fonts_shadow_color[i].blue, cfg->osd->text.fonts_shadow_color[i].alpha); + } + g_print("\nDECORATION\n"); + g_print(" code: %i\n", cfg->osd->decoration.code); + g_print(" custom skin file: %s\n", cfg->osd->decoration.skin_file); + for ( i = 0 ; i < cfg->osd->decoration.colors->len ; i++ ) + { + aosd_color_t color = g_array_index( cfg->osd->decoration.colors , aosd_color_t , i ); + g_print(" color %i: %i,%i,%i (alpha %i)\n", i, color.red, color.green, color.blue, color.alpha); + } + g_print("\nEXTRA\n"); + g_print(" set: %i\n", cfg->set); + g_print("\n*******************************\n\n"); + return; +} +#endif + + +gint +aosd_cfg_load ( aosd_cfg_t * cfg ) +{ + ConfigDb *cfgfile = bmp_cfg_db_open(); + gint i = 0; + gint max_numcol; + + /* position */ + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "position_placement" , &(cfg->osd->position.placement) ) ) + cfg->osd->position.placement = AOSD_POSITION_PLACEMENT_TOPLEFT; + + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "position_offset_x" , &(cfg->osd->position.offset_x) ) ) + cfg->osd->position.offset_x = 0; + + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "position_offset_y" , &(cfg->osd->position.offset_y) ) ) + cfg->osd->position.offset_y = 0; + + /* animation */ + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "animation_timing_display" , &(cfg->osd->animation.timing_display) ) ) + cfg->osd->animation.timing_display = 3000; + + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "animation_timing_fadein" , &(cfg->osd->animation.timing_fadein) ) ) + cfg->osd->animation.timing_fadein = 300; + + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "animation_timing_fadeout" , &(cfg->osd->animation.timing_fadeout) ) ) + cfg->osd->animation.timing_fadeout = 300; + + /* text */ + for ( i = 0 ; i < AOSD_TEXT_FONTS_NUM ; i++ ) + { + gchar *color_str = NULL; + gchar *key_str = NULL; + key_str = g_strdup_printf( "text_fonts_name_%i" , i ); + if ( !bmp_cfg_db_get_string( cfgfile , "aosd" , key_str , &(cfg->osd->text.fonts_name[i]) ) ) + cfg->osd->text.fonts_name[i] = g_strdup( "Sans 26" ); + g_free( key_str ); + key_str = g_strdup_printf( "text_fonts_color_%i" , i ); + if ( !bmp_cfg_db_get_string( cfgfile , "aosd" , key_str , &color_str ) ) + color_str = g_strdup( "65535,65535,65535,65535" ); /* white , alpha 100% */ + aosd_cfg_util_str_to_color( color_str , &(cfg->osd->text.fonts_color[i]) ); + g_free( key_str ); + g_free( color_str ); + key_str = g_strdup_printf( "text_fonts_draw_shadow_%i" , i ); + if ( !bmp_cfg_db_get_bool( cfgfile , "aosd" , key_str , &(cfg->osd->text.fonts_draw_shadow[i]) ) ) + cfg->osd->text.fonts_draw_shadow[i] = TRUE; + g_free( key_str ); + key_str = g_strdup_printf( "text_fonts_shadow_color_%i" , i ); + if ( !bmp_cfg_db_get_string( cfgfile , "aosd" , key_str , &color_str ) ) + color_str = g_strdup( "0,0,0,32767" ); /* black , alpha 50% */ + aosd_cfg_util_str_to_color( color_str , &(cfg->osd->text.fonts_shadow_color[i]) ); + g_free( key_str ); + g_free( color_str ); + } + + /* decoration */ + if ( !bmp_cfg_db_get_int( cfgfile , "aosd" , + "decoration_code" , &(cfg->osd->decoration.code) ) ) + cfg->osd->decoration.code = aosd_deco_style_get_first_code(); + + if ( !bmp_cfg_db_get_string( cfgfile , "aosd" , + "decoration_skin_file" , &(cfg->osd->decoration.skin_file) ) ) + cfg->osd->decoration.skin_file = g_strdup( "" ); + + /* decoration - colors */ + max_numcol = aosd_deco_style_get_max_numcol(); + for ( i = 0 ; i < max_numcol ; i++ ) + { + gchar *key_str = NULL; + gchar *color_str = NULL; + aosd_color_t color; + key_str = g_strdup_printf( "decoration_color_%i" , i ); + if ( !bmp_cfg_db_get_string( cfgfile , "aosd" , key_str , &color_str ) ) + { + /* we have different default values for the decoration colors */ + switch ( i ) + { + case 0: + color_str = g_strdup( "0,0,65535,32767" ); /* blue , alpha 50% */ + break; + case 1: + color_str = g_strdup( "65535,65535,65535,65535" ); /* white , alpha 100% */ + break; + case 2: + color_str = g_strdup( "51400,51400,51400,65535" ); /* gray , alpha 100% */ + break; + default: + color_str = g_strdup( "51400,51400,51400,65535" ); /* gray , alpha 100% */ + break; + } + } + aosd_cfg_util_str_to_color( color_str , &color ); + g_array_insert_val( cfg->osd->decoration.colors , i , color ); + } + + bmp_cfg_db_close( cfgfile ); + + /* the config object has been filled with information */ + cfg->set = TRUE; + + return 0; +} + + +gint +aosd_cfg_save ( aosd_cfg_t * cfg ) +{ + ConfigDb *cfgfile = bmp_cfg_db_open(); + gint i = 0; + gint max_numcol; + + if ( cfg->set == FALSE ) + return -1; + + /* position */ + bmp_cfg_db_set_int( cfgfile , "aosd" , + "position_placement" , cfg->osd->position.placement ); + + bmp_cfg_db_set_int( cfgfile , "aosd" , + "position_offset_x" , cfg->osd->position.offset_x ); + + bmp_cfg_db_set_int( cfgfile , "aosd" , + "position_offset_y" , cfg->osd->position.offset_y ); + + /* animation */ + bmp_cfg_db_set_int( cfgfile , "aosd" , + "animation_timing_display" , cfg->osd->animation.timing_display ); + + bmp_cfg_db_set_int( cfgfile , "aosd" , + "animation_timing_fadein" , cfg->osd->animation.timing_fadein ); + + bmp_cfg_db_set_int( cfgfile , "aosd" , + "animation_timing_fadeout" , cfg->osd->animation.timing_fadeout ); + + /* text */ + for ( i = 0 ; i < AOSD_TEXT_FONTS_NUM ; i++ ) + { + gchar *color_str = NULL; + gchar *key_str = NULL; + key_str = g_strdup_printf( "text_fonts_name_%i" , i ); + bmp_cfg_db_set_string( cfgfile , "aosd" , + key_str , cfg->osd->text.fonts_name[i] ); + g_free( key_str ); + key_str = g_strdup_printf( "text_fonts_color_%i" , i ); + aosd_cfg_util_color_to_str( cfg->osd->text.fonts_color[i] , &color_str ); + bmp_cfg_db_set_string( cfgfile , "aosd" , + key_str , color_str ); + g_free( key_str ); + g_free( color_str ); + key_str = g_strdup_printf( "text_fonts_draw_shadow_%i" , i ); + bmp_cfg_db_set_bool( cfgfile , "aosd" , + key_str , cfg->osd->text.fonts_draw_shadow[i] ); + g_free( key_str ); + key_str = g_strdup_printf( "text_fonts_shadow_color_%i" , i ); + aosd_cfg_util_color_to_str( cfg->osd->text.fonts_shadow_color[i] , &color_str ); + bmp_cfg_db_set_string( cfgfile , "aosd" , + key_str , color_str ); + g_free( key_str ); + g_free( color_str ); + } + + /* decoration */ + bmp_cfg_db_set_int( cfgfile , "aosd" , + "decoration_code" , cfg->osd->decoration.code ); + + bmp_cfg_db_set_string( cfgfile , "aosd" , + "decoration_skin_file" , cfg->osd->decoration.skin_file ); + + /* decoration - colors */ + max_numcol = aosd_deco_style_get_max_numcol(); + for ( i = 0 ; i < max_numcol ; i++ ) + { + gchar *key_str = NULL; + gchar *color_str = NULL; + aosd_color_t color = g_array_index( cfg->osd->decoration.colors , aosd_color_t , i ); + key_str = g_strdup_printf( "decoration_color_%i" , i ); + aosd_cfg_util_color_to_str( color , &color_str ); + bmp_cfg_db_set_string( cfgfile , "aosd" , + key_str , color_str ); + g_free( key_str ); + g_free( color_str ); + } + + bmp_cfg_db_close( cfgfile ); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_cfg.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,125 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_CFG_H +#define _I_AOSD_CFG_H 1 + +#include "aosd_common.h" +#include <glib.h> + +/* in this release only one user font is supported */ +#define AOSD_TEXT_FONTS_NUM 1 + +enum +{ + AOSD_POSITION_PLACEMENT_TOPLEFT = 1, + AOSD_POSITION_PLACEMENT_TOP, + AOSD_POSITION_PLACEMENT_TOPRIGHT, + AOSD_POSITION_PLACEMENT_MIDDLELEFT, + AOSD_POSITION_PLACEMENT_MIDDLE, + AOSD_POSITION_PLACEMENT_MIDDLERIGHT, + AOSD_POSITION_PLACEMENT_BOTTOMLEFT, + AOSD_POSITION_PLACEMENT_BOTTOM, + AOSD_POSITION_PLACEMENT_BOTTOMRIGHT +}; + + +typedef struct +{ + guint16 red; + guint16 green; + guint16 blue; + guint16 alpha; +} +aosd_color_t; + + +/* config portion containing osd decoration information */ +typedef struct +{ + gint code; + GArray *colors; + gchar *skin_file; +} +aosd_cfg_osd_decoration_t; + + +/* config portion containing osd text information */ +typedef struct +{ + gchar *fonts_name[AOSD_TEXT_FONTS_NUM]; + aosd_color_t fonts_color[AOSD_TEXT_FONTS_NUM]; + gboolean fonts_draw_shadow[AOSD_TEXT_FONTS_NUM]; + aosd_color_t fonts_shadow_color[AOSD_TEXT_FONTS_NUM]; +} +aosd_cfg_osd_text_t; + + +/* config portion containing osd animation information */ +typedef struct +{ + gint timing_display; + gint timing_fadein; + gint timing_fadeout; +} +aosd_cfg_osd_animation_t; + + +/* config portion containing osd position information */ +typedef struct +{ + gint placement; + gint offset_x; + gint offset_y; +} +aosd_cfg_osd_position_t; + + +/* config portion containing all information */ +typedef struct +{ + aosd_cfg_osd_position_t position; + aosd_cfg_osd_animation_t animation; + aosd_cfg_osd_text_t text; + aosd_cfg_osd_decoration_t decoration; +} +aosd_cfg_osd_t; + + +/* config portion containing all config information */ +typedef struct +{ + gboolean set; + + aosd_cfg_osd_t * osd; +} +aosd_cfg_t; + + +/* API */ +aosd_cfg_t * aosd_cfg_new ( void ); +void aosd_cfg_delete ( aosd_cfg_t * cfg ); +aosd_cfg_osd_t * aosd_cfg_osd_new( void ); +void aosd_cfg_osd_delete ( aosd_cfg_osd_t * cfg_osd ); +aosd_cfg_osd_t * aosd_cfg_osd_copy ( aosd_cfg_osd_t * cfg_osd ); +gint aosd_cfg_load ( aosd_cfg_t * cfg ); +gint aosd_cfg_save ( aosd_cfg_t * cfg ); + +#endif /* !_I_AOSD_CFG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_common.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,35 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_COMMON_H +#define _I_AOSD_COMMON_H 1 + +#ifdef DEBUG +#include <stdio.h> +#define DEBUGMSG(...) { fprintf(stderr, "statusicon(%s:%s:%d): ", __FILE__, __FUNCTION__, (int) __LINE__); fprintf(stderr, __VA_ARGS__); } +#else +#define DEBUGMSG(...) +#endif /* DEBUG */ + +#include "../../config.h" + +#define AOSD_VERSION_PLUGIN "0.1" + +#endif /* !_I_AOSD_COMMON_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_osd.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,344 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#include "aosd_osd.h" +#include "aosd_style.h" +#include "aosd_style_private.h" +#include "aosd_cfg.h" +#include <glib.h> +#include <X11/Xlib.h> +#include <cairo/cairo.h> +#include <pango/pangocairo.h> +#include <gdk/gdk.h> +#include <pthread.h> +#include <stdlib.h> +#include <sys/time.h> +#include "ghosd.h" +#include "ghosd-text.h" + + +#define AOSD_STATUS_HIDDEN 0 +#define AOSD_STATUS_SHOWN 1 +#define AOSD_STATUS_UPDATE 2 + + +static pthread_t * aosd_thread = NULL; +static pthread_mutex_t aosd_status_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t aosd_status_cond = PTHREAD_COND_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; + + +typedef struct +{ + cairo_surface_t * surface; + float alpha; + void * user_data; + gint width; + gint height; + gint deco_code; +} +GhosdFadeData; + + +static void +aosd_fade_func ( Ghosd * osd , cairo_t * cr , void * user_data ) +{ + GhosdFadeData *fade_data = user_data; + + if ( fade_data->surface == NULL ) + { + cairo_t *rendered_cr; + 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 ); + cairo_destroy( rendered_cr ); + } + + cairo_set_source_surface( cr , fade_data->surface , 0 , 0 ); + cairo_paint_with_alpha( cr , fade_data->alpha ); +} + + +static void * +aosd_thread_func ( void * arg ) +{ + 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, pos_x = 0, pos_y = 0; + gint pad_left = 0 , pad_right = 0 , pad_top = 0 , pad_bottom = 0; + const gint screen_width = gdk_screen_get_width( gdk_screen_get_default() ); + const gint screen_height = gdk_screen_get_height( gdk_screen_get_default() ); + 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; + + /* pick padding from selected decoration style */ + aosd_deco_style_get_padding( cfg_osd->decoration.code , + &pad_top , &pad_bottom , &pad_left , &pad_right ); + + max_width = screen_width - pad_left - pad_right - abs(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 = ghosd_new(); + + /* osd position */ + switch ( cfg_osd->position.placement ) + { + case AOSD_POSITION_PLACEMENT_TOP: + pos_x = (screen_width - (layout_width + pad_left + pad_right)) / 2; + pos_y = 0; + break; + case AOSD_POSITION_PLACEMENT_TOPRIGHT: + pos_x = screen_width - (layout_width + pad_left + pad_right); + pos_y = 0; + break; + case AOSD_POSITION_PLACEMENT_MIDDLELEFT: + pos_x = 0; + pos_y = (screen_height - (layout_height + pad_top + pad_bottom)) / 2; + break; + case AOSD_POSITION_PLACEMENT_MIDDLE: + pos_x = (screen_width - (layout_width + pad_left + pad_right)) / 2; + pos_y = (screen_height - (layout_height + pad_top + pad_bottom)) / 2; + break; + case AOSD_POSITION_PLACEMENT_MIDDLERIGHT: + pos_x = screen_width - (layout_width + pad_left + pad_right); + pos_y = (screen_height - (layout_height + pad_top + pad_bottom)) / 2; + break; + case AOSD_POSITION_PLACEMENT_BOTTOMLEFT: + pos_x = 0; + pos_y = screen_height - (layout_height + pad_top + pad_bottom); + break; + case AOSD_POSITION_PLACEMENT_BOTTOM: + pos_x = (screen_width - (layout_width + pad_left + pad_right)) / 2; + pos_y = screen_height - (layout_height + pad_top + pad_bottom); + break; + case AOSD_POSITION_PLACEMENT_BOTTOMRIGHT: + pos_x = screen_width - (layout_width + pad_left + pad_right); + pos_y = screen_height - (layout_height + pad_top + pad_bottom); + break; + case AOSD_POSITION_PLACEMENT_TOPLEFT: + default: + pos_x = 0; + pos_y = 0; + break; + } + + /* add offset to position */ + pos_x += cfg_osd->position.offset_x; + pos_y += 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 ); + + /* the aosd_status must be checked during the fade and display process + (if another message arrives, the current transition must be abandoned ) */ + + 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 ); + + /* show the osd (with alpha 0, invisible) */ + ghosd_show( osd ); + + if ( stop_now != TRUE ) + { + /* fade in */ + for ( fade_data.alpha = 0 ; fade_data.alpha < 1.0 ; fade_data.alpha += dalpha_in ) + { + pthread_mutex_lock( &aosd_status_mutex ); + if ( aosd_status == AOSD_STATUS_UPDATE ) + { pthread_mutex_unlock( &aosd_status_mutex ); stop_now = TRUE; break; } + pthread_mutex_unlock( &aosd_status_mutex ); + + 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 ); + } + } + + 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_UPDATE ) + { 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_UPDATE ) + { 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 ); + if ( aosd_status == AOSD_STATUS_UPDATE ) + { + aosd_status = AOSD_STATUS_SHOWN; + pthread_mutex_unlock( &aosd_status_mutex ); + pthread_cond_signal( &aosd_status_cond ); + } + else + { + 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); +} + + +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 ) + { + thread_data->cfg_osd = aosd_cfg_osd_copy( cfg_osd ); + thread_data->cfg_is_copied = TRUE; + } + 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_UPDATE; + pthread_cond_wait( &aosd_status_cond , &aosd_status_mutex ); + } + 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)); + + pthread_create( aosd_thread , NULL , aosd_thread_func , thread_data ); + return 0; +} + + +void +aosd_shutdown ( void ) +{ + if ( aosd_thread != NULL ) + { + 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_UPDATE; + pthread_cond_wait( &aosd_status_cond , &aosd_status_mutex ); + } + 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 */ + } + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_osd.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,32 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_OSD_H +#define _I_AOSD_OSD_H 1 + +#include "aosd_common.h" +#include "aosd_cfg.h" +#include <glib.h> + + +gint aosd_display ( gchar * markup_string , aosd_cfg_osd_t * cfg_osd , gboolean copy_cfg ); +void aosd_shutdown ( void ); + +#endif /* !_I_AOSD_OSD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_style.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,332 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#include "aosd_style.h" +#include "aosd_style_private.h" +#include "aosd_cfg.h" +#include <glib.h> +#include <glib/gi18n.h> +#include <X11/Xlib.h> +#include <cairo/cairo.h> +#include <pango/pangocairo.h> +#include "ghosd.h" +#include "ghosd-text.h" + + +/* HOW TO ADD A NEW DECORATION STYLE + -------------------------------------------------------------------------- + First, add a new decoration style code; then, provide the decoration style + information by adding a new entry in the aosd_deco_styles[] array (name, + render function, etc.); add the new decoration style code in the array + of decoration style codes, and update the define containing the array size. + The render function uses three parameters; the Ghosd instance, the cairo + object you use to draw, and a aosd_deco_style_data_t object that contains + user-defined options (look into aosd_style.h and aosd_cfg.h for details). + Have fun! :) +*/ + + +/* decoration style codes ( the code values do not need to be sequential ) */ +enum +{ + AOSD_DECO_STYLE_RECT = 0, + AOSD_DECO_STYLE_ROUNDRECT = 1, + AOSD_DECO_STYLE_CONCAVERECT = 2 +}; + +/* decoration style codes array size */ +#define AOSD_DECO_STYLE_CODES_ARRAY_SIZE 3 + +/* decoration style codes array */ +gint aosd_deco_style_codes[] = +{ + AOSD_DECO_STYLE_RECT, + AOSD_DECO_STYLE_ROUNDRECT, + AOSD_DECO_STYLE_CONCAVERECT +}; + +/* prototypes of render functions */ +static void aosd_deco_rfunc_rect ( Ghosd * , cairo_t * , aosd_deco_style_data_t * ); +static void aosd_deco_rfunc_roundrect ( Ghosd * , cairo_t * , aosd_deco_style_data_t * ); +static void aosd_deco_rfunc_concaverect ( Ghosd * , cairo_t * , aosd_deco_style_data_t * ); + +/* map decoration style codes to decoration objects */ +aosd_deco_style_t aosd_deco_styles[] = +{ + [AOSD_DECO_STYLE_RECT] = { N_("Rectangle") , + aosd_deco_rfunc_rect , + 2 , { 10 , 10 , 10 , 10 } }, + + [AOSD_DECO_STYLE_ROUNDRECT] = { N_("Rounded Rectangle") , + aosd_deco_rfunc_roundrect , + 2 , { 10 , 10 , 10 , 10 } }, + + [AOSD_DECO_STYLE_CONCAVERECT] = { N_("Concave Rectangle") , + aosd_deco_rfunc_concaverect , + 2 , { 10 , 10 , 10 , 10 } } +}; + + + +/* DECORATION STYLE API */ + + +void +aosd_deco_style_get_codes_array ( gint ** array , gint * array_size ) +{ + *array = aosd_deco_style_codes; + *array_size = AOSD_DECO_STYLE_CODES_ARRAY_SIZE; + return; +} + + +void +aosd_deco_style_get_padding ( gint deco_code , + gint * ptop , gint * pbottom , + gint * pleft , gint * pright ) +{ + if ( ptop != NULL ) *ptop = aosd_deco_styles[deco_code].padding.top; + if ( pbottom != NULL ) *pbottom = aosd_deco_styles[deco_code].padding.bottom; + if ( pleft != NULL ) *pleft = aosd_deco_styles[deco_code].padding.left; + if ( pright != NULL ) *pright = aosd_deco_styles[deco_code].padding.right; + return; +} + + +const gchar * +aosd_deco_style_get_desc ( gint deco_code ) +{ + return aosd_deco_styles[deco_code].desc; +} + + +gint +aosd_deco_style_get_numcol ( gint deco_code ) +{ + return aosd_deco_styles[deco_code].colors_num; +} + + +void +aosd_deco_style_render ( gint deco_code , gpointer ghosd , gpointer cr , gpointer user_data ) +{ + aosd_deco_styles[deco_code].render_func( (Ghosd*)ghosd , (cairo_t*)cr , user_data ); +} + + +gint +aosd_deco_style_get_first_code ( void ) +{ + return AOSD_DECO_STYLE_RECT; +} + + +gint +aosd_deco_style_get_max_numcol ( void ) +{ + gint i = 0; + gint max_numcol = 0; + + for ( i = 0 ; i < AOSD_DECO_STYLE_CODES_ARRAY_SIZE ; i++ ) + { + gint numcol = aosd_deco_style_get_numcol( aosd_deco_style_codes[i] ); + if ( numcol > max_numcol ) + max_numcol = numcol; + } + + return max_numcol; +} + + + +/* RENDER FUNCTIONS */ + +static void +aosd_deco_rfunc_rect( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data ) +{ + /* decoration information + ---------------------- + draws a simple rectangular decoration; uses 2 colors + (user color 1 and 2) and 1 font (user font 1), with optional shadow + */ + PangoLayout *osd_layout = data->layout; + aosd_color_t color0 = g_array_index( data->decoration->colors , aosd_color_t , 0 ); + aosd_color_t color1 = g_array_index( data->decoration->colors , aosd_color_t , 1 ); + aosd_color_t textcolor0 = data->text->fonts_color[0]; + aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0]; + gboolean draw_shadow = data->text->fonts_draw_shadow[0]; + gint width = 0, height = 0; + + pango_layout_get_pixel_size( osd_layout , &width , &height ); + + /* draw rectangle container */ + cairo_set_source_rgba( cr , (gdouble)color0.red / 65535 , (gdouble)color0.green / 65535 , + (gdouble)color0.blue / 65535 , (gdouble)color0.alpha / 65535 ); + cairo_rectangle( cr , 0 , 0 , + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.left + width + + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.right, + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.top + height + + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.bottom ); + cairo_fill_preserve( cr ); + cairo_set_source_rgba( cr , (gdouble)color1.red / 65535 , (gdouble)color1.green / 65535 , + (gdouble)color1.blue / 65535 , (gdouble)color1.alpha / 65535 ); + cairo_stroke( cr ); + + if ( draw_shadow == TRUE ) + { + /* draw text shadow */ + cairo_set_source_rgba( cr , (gdouble)shadowcolor0.red / 65535 , (gdouble)shadowcolor0.green / 65535 , + (gdouble)shadowcolor0.blue / 65535 , (gdouble)shadowcolor0.alpha / 65535 ); + cairo_move_to( cr, + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.left + 2 , + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.top + 2 ); + pango_cairo_show_layout( cr , osd_layout ); + } + + /* draw text */ + cairo_set_source_rgba( cr , (gdouble)textcolor0.red / 65535 , (gdouble)textcolor0.green / 65535 , + (gdouble)textcolor0.blue / 65535 , (gdouble)textcolor0.alpha / 65535 ); + cairo_move_to( cr, + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.top ); + pango_cairo_show_layout( cr , osd_layout ); +} + + +static void +aosd_deco_rfunc_roundrect ( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data ) +{ + /* decoration information + ---------------------- + draws a rectangular decoration with rounded angles; uses 2 colors + (user color 1 and 2) and 1 font (user font 1), with optional shadow + */ + PangoLayout *osd_layout = data->layout; + aosd_color_t color0 = g_array_index( data->decoration->colors , aosd_color_t , 0 ); + aosd_color_t color1 = g_array_index( data->decoration->colors , aosd_color_t , 1 ); + aosd_color_t textcolor0 = data->text->fonts_color[0]; + aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0]; + gboolean draw_shadow = data->text->fonts_draw_shadow[0]; + gint width = 0, height = 0; + + pango_layout_get_pixel_size( osd_layout , &width , &height ); + + /* draw rounded-rectangle container */ + cairo_set_source_rgba( cr , (gdouble)color0.red / 65535 , (gdouble)color0.green / 65535 , + (gdouble)color0.blue / 65535 , (gdouble)color0.alpha / 65535 ); + cairo_move_to( cr , aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , 0 ); + cairo_arc( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top , + 10. , -G_PI_2 , 0. ); + cairo_arc( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top + height , + 10. , -4. * G_PI_2 , -3. * G_PI_2 ); + cairo_arc( cr , aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top + height , + 10. , -3. * G_PI_2 , -2. * G_PI_2 ); + cairo_arc( cr , aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top , + 10. , -2. * G_PI_2 , -G_PI_2 ); + cairo_close_path( cr ); + cairo_fill_preserve( cr ); + cairo_set_source_rgba( cr , (gdouble)color1.red / 65535 , (gdouble)color1.green / 65535 , + (gdouble)color1.blue / 65535 , (gdouble)color1.alpha / 65535 ); + cairo_stroke( cr ); + + if ( draw_shadow == TRUE ) + { + /* draw text shadow */ + cairo_set_source_rgba( cr , (gdouble)shadowcolor0.red / 65535 , (gdouble)shadowcolor0.green / 65535 , + (gdouble)shadowcolor0.blue / 65535 , (gdouble)shadowcolor0.alpha / 65535 ); + cairo_move_to( cr , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left + 2 , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top + 2 ); + pango_cairo_show_layout( cr , osd_layout ); + } + + /* draw text */ + cairo_set_source_rgba( cr , (gdouble)textcolor0.red / 65535 , (gdouble)textcolor0.green / 65535 , + (gdouble)textcolor0.blue / 65535 , (gdouble)textcolor0.alpha / 65535 ); + cairo_move_to( cr , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top ); + pango_cairo_show_layout( cr , osd_layout ); +} + + +static void +aosd_deco_rfunc_concaverect ( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data ) +{ + /* decoration information + ---------------------- + draws a rectangle with concave angles; uses 2 colors + (user color 1 and 2) and 1 font (user font 1), with optional shadow + */ + PangoLayout *osd_layout = data->layout; + aosd_color_t color0 = g_array_index( data->decoration->colors , aosd_color_t , 0 ); + aosd_color_t color1 = g_array_index( data->decoration->colors , aosd_color_t , 1 ); + aosd_color_t textcolor0 = data->text->fonts_color[0]; + aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0]; + gboolean draw_shadow = data->text->fonts_draw_shadow[0]; + gint width = 0, height = 0; + + pango_layout_get_pixel_size( osd_layout , &width , &height ); + + /* draw jigsaw-piece-like container */ + cairo_set_source_rgba( cr , (gdouble)color0.red / 65535 , (gdouble)color0.green / 65535 , + (gdouble)color0.blue / 65535 , (gdouble)color0.alpha / 65535 ); + cairo_move_to( cr , aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left , 0 ); + cairo_arc_negative( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + 2 , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top - 2 , + 8. , -G_PI_2 , 0. ); + cairo_arc_negative( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + 2 , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top + height + 2 , + 8. , -4. * G_PI_2 , -3. * G_PI_2 ); + cairo_arc_negative( cr , aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left - 2 , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top + height + 2 , + 8. , -3. * G_PI_2 , -2. * G_PI_2 ); + cairo_arc_negative( cr , aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left - 2 , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top - 2 , + 8. , -2. * G_PI_2 , -G_PI_2 ); + cairo_close_path( cr ); + cairo_fill_preserve( cr ); + cairo_set_source_rgba( cr , (gdouble)color1.red / 65535 , (gdouble)color1.green / 65535 , + (gdouble)color1.blue / 65535 , (gdouble)color1.alpha / 65535 ); + cairo_stroke( cr ); + + if ( draw_shadow == TRUE ) + { + /* draw text shadow */ + cairo_set_source_rgba( cr , (gdouble)shadowcolor0.red / 65535 , (gdouble)shadowcolor0.green / 65535 , + (gdouble)shadowcolor0.blue / 65535 , (gdouble)shadowcolor0.alpha / 65535 ); + cairo_move_to( cr , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + 2 , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top + 2 ); + pango_cairo_show_layout( cr , osd_layout ); + } + + /* draw text */ + cairo_set_source_rgba( cr , (gdouble)textcolor0.red / 65535 , (gdouble)textcolor0.green / 65535 , + (gdouble)textcolor0.blue / 65535 , (gdouble)textcolor0.alpha / 65535 ); + cairo_move_to( cr , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left , + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top ); + pango_cairo_show_layout( cr , osd_layout ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_style.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,39 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_STYLE_H +#define _I_AOSD_STYLE_H 1 + +#include "aosd_common.h" +#include <glib.h> + + +/* decoration style public API */ +void aosd_deco_style_get_codes_array ( gint ** , gint * ); +void aosd_deco_style_get_padding ( gint , gint * , gint * , gint * , gint * ); +const gchar * aosd_deco_style_get_desc ( gint ); +gint aosd_deco_style_get_numcol ( gint ); +void aosd_deco_style_render ( gint , gpointer , gpointer , gpointer ); /* opaque */ + +gint aosd_deco_style_get_first_code ( void ); +gint aosd_deco_style_get_max_numcol ( void ); + + +#endif /* !_I_AOSD_STYLE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_style_private.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,71 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_STYLE_PRIVATE_H +#define _I_AOSD_STYLE_PRIVATE_H 1 + +#include "aosd_common.h" +#include "aosd_cfg.h" +#include <glib.h> +#include <cairo/cairo.h> +#include <pango/pangocairo.h> +#include "ghosd.h" + + +/* decoration render function parameter object + ---------------------------------------------------------- + layout pango layout that contains OSD text + text user-defined options for OSD text + decoration user-defined options for OSD decorations +*/ +typedef struct +{ + PangoLayout * layout; + aosd_cfg_osd_text_t * text; + aosd_cfg_osd_decoration_t * decoration; +} +aosd_deco_style_data_t; + + +/* decoration object + ---------------------------------------------------------- + desc description + render_func render function used to draw the decoration + colors_num number of user-definable colors + padding drawable space available around the text +*/ +typedef struct +{ + const gchar * desc; + void (*render_func)( Ghosd * , cairo_t * , aosd_deco_style_data_t * ); + gint colors_num; + struct + { + gint top; + gint bottom; + gint left; + gint right; + } + padding; +} +aosd_deco_style_t; + + +#endif /* !_I_AOSD_STYLE_PRIVATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_ui.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,867 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#include "aosd_ui.h" +#include "aosd_style.h" +#include "aosd_cfg.h" +#include "aosd_osd.h" +#include <glib.h> +#include <glib/gi18n.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> + + +extern aosd_cfg_t * global_config; + + +/*************************************************************/ +/* small callback system used by the configuration interface */ +typedef void (*aosd_ui_cb_func_t)( GtkWidget * , aosd_cfg_t * ); + +typedef struct +{ + aosd_ui_cb_func_t func; + GtkWidget * widget; +} +aosd_ui_cb_t; + +static void +aosd_callback_list_add ( GList ** list , GtkWidget * widget , aosd_ui_cb_func_t func ) +{ + aosd_ui_cb_t *cb = g_malloc(sizeof(aosd_ui_cb_t)); + cb->widget = widget; + cb->func = func; + *list = g_list_append( *list , cb ); + return; +} + +static void +aosd_callback_list_run ( GList * list , aosd_cfg_t * cfg ) +{ + while ( list != NULL ) + { + aosd_ui_cb_t *cb = (aosd_ui_cb_t*)list->data; + cb->func( cb->widget , cfg ); + list = g_list_next( list ); + } + return; +} + +static void +aosd_callback_list_free ( GList * list ) +{ + GList *list_top = list; + while ( list != NULL ) + { + g_free( (aosd_ui_cb_t*)list->data ); + list = g_list_next( list ); + } + g_list_free( list_top ); + return; +} +/*************************************************************/ + + + +static gboolean +aosd_cb_configure_position_expose ( GtkWidget * darea , + GdkEventExpose * event , + gpointer coord_gp ) +{ + gint coord = GPOINTER_TO_INT(coord_gp); + gdk_draw_rectangle( GDK_DRAWABLE(darea->window) , + darea->style->black_gc , TRUE , + (coord % 3) * 10 , (coord / 3) * 16 , 20 , 8 ); + return FALSE; +} + + +static void +aosd_cb_configure_position_placement_commit ( GtkWidget * table , aosd_cfg_t * cfg ) +{ + GList *placbt_list = gtk_container_get_children( GTK_CONTAINER(table) ); + GList *list_iter = placbt_list; + + while ( list_iter != NULL ) + { + GtkWidget *placbt = list_iter->data; + if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(placbt) ) == TRUE ) + { + cfg->osd->position.placement = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(placbt),"value")); + break; + } + list_iter = g_list_next( list_iter ); + } + + g_list_free( placbt_list ); + return; +} + + +static void +aosd_cb_configure_position_offset_commit ( GtkWidget * table , aosd_cfg_t * cfg ) +{ + cfg->osd->position.offset_x = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(table),"offx")) ); + cfg->osd->position.offset_y = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(table),"offy")) ); + return; +} + + +static GtkWidget * +aosd_ui_configure_position ( aosd_cfg_t * cfg , GList ** cb_list ) +{ + GtkWidget *pos_vbox; + GtkWidget *pos_placement_frame, *pos_placement_hbox, *pos_placement_table; + GtkWidget *pos_placement_bt[9], *pos_placement_bt_darea[9]; + GtkWidget *pos_offset_table, *pos_offset_x_label, *pos_offset_x_spinbt; + GtkWidget *pos_offset_y_label, *pos_offset_y_spinbt; + gint i = 0; + + pos_vbox = gtk_vbox_new( FALSE , 0 ); + gtk_container_set_border_width( GTK_CONTAINER(pos_vbox) , 6 ); + + pos_placement_frame = gtk_frame_new( _("Placement") ); + pos_placement_hbox = gtk_hbox_new( FALSE , 0 ); + gtk_container_set_border_width( GTK_CONTAINER(pos_placement_hbox) , 6 ); + gtk_container_add( GTK_CONTAINER(pos_placement_frame) , pos_placement_hbox ); + gtk_box_pack_start( GTK_BOX(pos_vbox) , pos_placement_frame , FALSE , FALSE , 0 ); + + pos_placement_table = gtk_table_new( 3 , 3 , TRUE ); + for ( i = 0 ; i < 9 ; i++ ) + { + if ( i == 0 ) + pos_placement_bt[i] = gtk_radio_button_new( NULL ); + else + pos_placement_bt[i] = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(pos_placement_bt[0]) ); + gtk_toggle_button_set_mode( GTK_TOGGLE_BUTTON(pos_placement_bt[i]) , FALSE ); + pos_placement_bt_darea[i] = gtk_drawing_area_new(); + gtk_widget_set_size_request( pos_placement_bt_darea[i] , 40 , 40 ); + gtk_container_add( GTK_CONTAINER(pos_placement_bt[i]) , pos_placement_bt_darea[i] ); + g_signal_connect( G_OBJECT(pos_placement_bt_darea[i]) , "expose-event" , + G_CALLBACK(aosd_cb_configure_position_expose) , GINT_TO_POINTER(i) ); + gtk_table_attach( GTK_TABLE(pos_placement_table) , pos_placement_bt[i] , + (i % 3) , (i % 3) + 1 , (i / 3) , (i / 3) + 1 , + GTK_FILL , GTK_FILL , 0 , 0 ); + g_object_set_data( G_OBJECT(pos_placement_bt[i]) , "value" , GINT_TO_POINTER(i+1) ); + if ( cfg->osd->position.placement == (i+1) ) + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(pos_placement_bt[i]) , TRUE ); + } + gtk_box_pack_start( GTK_BOX(pos_placement_hbox) , pos_placement_table , FALSE , FALSE , 0 ); + aosd_callback_list_add( cb_list , pos_placement_table , aosd_cb_configure_position_placement_commit ); + + gtk_box_pack_start( GTK_BOX(pos_placement_hbox) , gtk_vseparator_new() , FALSE , FALSE , 6 ); + + pos_offset_table = gtk_table_new( 2 , 2 , FALSE ); + gtk_table_set_row_spacings( GTK_TABLE(pos_offset_table) , 4 ); + gtk_table_set_col_spacings( GTK_TABLE(pos_offset_table) , 4 ); + pos_offset_x_label = gtk_label_new( _( "Relative X offset:" ) ); + gtk_table_attach( GTK_TABLE(pos_offset_table) , pos_offset_x_label , + 0 , 1 , 0 , 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + pos_offset_x_spinbt = gtk_spin_button_new_with_range( -9999 , 9999 , 1 ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(pos_offset_x_spinbt) , cfg->osd->position.offset_x ); + gtk_table_attach( GTK_TABLE(pos_offset_table) , pos_offset_x_spinbt , + 1 , 2 , 0 , 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + g_object_set_data( G_OBJECT(pos_offset_table) , "offx" , pos_offset_x_spinbt ); + pos_offset_y_label = gtk_label_new( _( "Relative Y offset:" ) ); + gtk_table_attach( GTK_TABLE(pos_offset_table) , pos_offset_y_label , + 0 , 1 , 1 , 2 , GTK_FILL , GTK_FILL , 0 , 0 ); + pos_offset_y_spinbt = gtk_spin_button_new_with_range( -9999 , 9999 , 1 ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(pos_offset_y_spinbt) , cfg->osd->position.offset_y ); + gtk_table_attach( GTK_TABLE(pos_offset_table) , pos_offset_y_spinbt , + 1 , 2 , 1 , 2 , GTK_FILL , GTK_FILL , 0 , 0 ); + g_object_set_data( G_OBJECT(pos_offset_table) , "offy" , pos_offset_y_spinbt ); + gtk_box_pack_start( GTK_BOX(pos_placement_hbox) , pos_offset_table , FALSE , FALSE , 0 ); + aosd_callback_list_add( cb_list , pos_offset_table , aosd_cb_configure_position_offset_commit ); + + return pos_vbox; +} + + +static GtkWidget * +aosd_ui_configure_animation_timing ( gchar * label_string ) +{ + GtkWidget *hbox, *desc_label, *spinbt; + hbox = gtk_hbox_new( FALSE , 4 ); + desc_label = gtk_label_new( label_string ); + spinbt = gtk_spin_button_new_with_range( 0 , 99999 , 1 ); + gtk_box_pack_start( GTK_BOX(hbox) , desc_label , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(hbox) , spinbt , FALSE , FALSE , 0 ); + g_object_set_data( G_OBJECT(hbox) , "spinbt" , spinbt ); + return hbox; +} + + +static void +aosd_cb_configure_animation_timing_commit ( GtkWidget * timing_hbox , aosd_cfg_t * cfg ) +{ + cfg->osd->animation.timing_display = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(timing_hbox),"display")) ); + cfg->osd->animation.timing_fadein = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(timing_hbox),"fadein")) ); + cfg->osd->animation.timing_fadeout = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(timing_hbox),"fadeout")) ); + return; +} + + +static GtkWidget * +aosd_ui_configure_animation ( aosd_cfg_t * cfg , GList ** cb_list ) +{ + GtkWidget *ani_vbox; + GtkWidget *ani_timing_frame, *ani_timing_hbox; + GtkWidget *ani_timing_fadein_widget, *ani_timing_fadeout_widget, *ani_timing_stay_widget; + GtkSizeGroup *sizegroup; + + ani_vbox = gtk_vbox_new( FALSE , 0 ); + gtk_container_set_border_width( GTK_CONTAINER(ani_vbox) , 6 ); + + ani_timing_hbox = gtk_hbox_new( FALSE , 0 ); + ani_timing_frame = gtk_frame_new( _("Timing (ms)") ); + gtk_container_set_border_width( GTK_CONTAINER(ani_timing_hbox) , 6 ); + gtk_container_add( GTK_CONTAINER(ani_timing_frame) , ani_timing_hbox ); + gtk_box_pack_start( GTK_BOX(ani_vbox) , ani_timing_frame , FALSE , FALSE , 0 ); + + ani_timing_stay_widget = aosd_ui_configure_animation_timing( _("Display:") ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(g_object_get_data( + G_OBJECT(ani_timing_stay_widget),"spinbt")) , cfg->osd->animation.timing_display ); + gtk_box_pack_start( GTK_BOX(ani_timing_hbox) , ani_timing_stay_widget , TRUE , TRUE , 0 ); + gtk_box_pack_start( GTK_BOX(ani_timing_hbox) , gtk_vseparator_new() , FALSE , FALSE , 4 ); + ani_timing_fadein_widget = aosd_ui_configure_animation_timing( _("Fade in:") ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(g_object_get_data( + G_OBJECT(ani_timing_fadein_widget),"spinbt")) , cfg->osd->animation.timing_fadein ); + gtk_box_pack_start( GTK_BOX(ani_timing_hbox) , ani_timing_fadein_widget , TRUE , TRUE , 0 ); + gtk_box_pack_start( GTK_BOX(ani_timing_hbox) , gtk_vseparator_new() , FALSE , FALSE , 4 ); + ani_timing_fadeout_widget = aosd_ui_configure_animation_timing( _("Fade out:") ); + gtk_spin_button_set_value( GTK_SPIN_BUTTON(g_object_get_data( + G_OBJECT(ani_timing_fadeout_widget),"spinbt")) , cfg->osd->animation.timing_fadeout ); + gtk_box_pack_start( GTK_BOX(ani_timing_hbox) , ani_timing_fadeout_widget , TRUE , TRUE , 0 ); + g_object_set_data( G_OBJECT(ani_timing_hbox) , "display" , + g_object_get_data(G_OBJECT(ani_timing_stay_widget),"spinbt") ); + g_object_set_data( G_OBJECT(ani_timing_hbox) , "fadein" , + g_object_get_data(G_OBJECT(ani_timing_fadein_widget),"spinbt") ); + g_object_set_data( G_OBJECT(ani_timing_hbox) , "fadeout" , + g_object_get_data(G_OBJECT(ani_timing_fadeout_widget),"spinbt") ); + sizegroup = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL ); + gtk_size_group_add_widget( sizegroup , ani_timing_stay_widget ); + gtk_size_group_add_widget( sizegroup , ani_timing_fadein_widget ); + gtk_size_group_add_widget( sizegroup , ani_timing_fadeout_widget ); + aosd_callback_list_add( cb_list , ani_timing_hbox , aosd_cb_configure_animation_timing_commit ); + + return ani_vbox; +} + + +static void +aosd_cb_configure_text_font_shadow_toggle ( GtkToggleButton * shadow_togglebt , + gpointer shadow_colorbt ) +{ + if ( gtk_toggle_button_get_active( shadow_togglebt ) == TRUE ) + gtk_widget_set_sensitive( GTK_WIDGET(shadow_colorbt) , TRUE ); + else + gtk_widget_set_sensitive( GTK_WIDGET(shadow_colorbt) , FALSE ); + return; +} + + +static void +aosd_cb_configure_text_font_commit ( GtkWidget * fontbt , aosd_cfg_t * cfg ) +{ + gint fontnum = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(fontbt) , "fontnum" )); + GdkColor color, shadow_color; + cfg->osd->text.fonts_name[fontnum] = g_strdup( gtk_font_button_get_font_name(GTK_FONT_BUTTON(fontbt)) ); + gtk_color_button_get_color( + GTK_COLOR_BUTTON(g_object_get_data(G_OBJECT(fontbt),"color")) , &color ); + cfg->osd->text.fonts_color[fontnum].red = color.red; + cfg->osd->text.fonts_color[fontnum].green = color.green; + cfg->osd->text.fonts_color[fontnum].blue = color.blue; + cfg->osd->text.fonts_color[fontnum].alpha = gtk_color_button_get_alpha( + GTK_COLOR_BUTTON(g_object_get_data(G_OBJECT(fontbt),"color")) ); + cfg->osd->text.fonts_draw_shadow[fontnum] = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(fontbt),"use_shadow")) ); + gtk_color_button_get_color( + GTK_COLOR_BUTTON(g_object_get_data(G_OBJECT(fontbt),"shadow_color")) , &shadow_color ); + cfg->osd->text.fonts_shadow_color[fontnum].red = shadow_color.red; + cfg->osd->text.fonts_shadow_color[fontnum].green = shadow_color.green; + cfg->osd->text.fonts_shadow_color[fontnum].blue = shadow_color.blue; + cfg->osd->text.fonts_shadow_color[fontnum].alpha = gtk_color_button_get_alpha( + GTK_COLOR_BUTTON(g_object_get_data(G_OBJECT(fontbt),"shadow_color")) ); + return; +} + + +static GtkWidget * +aosd_ui_configure_text ( aosd_cfg_t * cfg , GList ** cb_list ) +{ + GtkWidget *tex_vbox; + GtkWidget *tex_font_table, *tex_font_frame; + GtkWidget *tex_font_label[3], *tex_font_fontbt[3]; + GtkWidget *tex_font_colorbt[3], *tex_font_shadow_togglebt[3]; + GtkWidget *tex_font_shadow_colorbt[3]; + GtkWidget *other_vbox; + gint i = 0; + + tex_vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(tex_vbox) , 6 ); + + tex_font_frame = gtk_frame_new( _("Fonts") ); + tex_font_table = gtk_table_new( 3 , 5 , FALSE ); + gtk_container_set_border_width( GTK_CONTAINER(tex_font_table) , 6 ); + gtk_table_set_row_spacings( GTK_TABLE(tex_font_table) , 4 ); + gtk_table_set_col_spacings( GTK_TABLE(tex_font_table) , 4 ); + for ( i = 0 ; i < AOSD_TEXT_FONTS_NUM ; i++ ) + { + GdkColor gcolor = { 0 , 0 , 0 , 0 }; + gchar *label_str = g_strdup_printf( "Font %i:" , i+1 ); + tex_font_label[i] = gtk_label_new( label_str ); + g_free( label_str ); + tex_font_fontbt[i] = gtk_font_button_new(); + gtk_font_button_set_show_style( GTK_FONT_BUTTON(tex_font_fontbt[i]) , TRUE ); + gtk_font_button_set_show_size( GTK_FONT_BUTTON(tex_font_fontbt[i]) , TRUE ); + gtk_font_button_set_use_font( GTK_FONT_BUTTON(tex_font_fontbt[i]) , FALSE ); + gtk_font_button_set_use_size( GTK_FONT_BUTTON(tex_font_fontbt[i]) , FALSE ); + gtk_font_button_set_font_name( GTK_FONT_BUTTON(tex_font_fontbt[i]) , cfg->osd->text.fonts_name[i] ); + tex_font_colorbt[i] = gtk_color_button_new(); + gcolor.red = cfg->osd->text.fonts_color[i].red; + gcolor.green = cfg->osd->text.fonts_color[i].green; + gcolor.blue = cfg->osd->text.fonts_color[i].blue; + gtk_color_button_set_use_alpha( GTK_COLOR_BUTTON(tex_font_colorbt[i]) , TRUE ); + gtk_color_button_set_color( GTK_COLOR_BUTTON(tex_font_colorbt[i]) , &gcolor ); + gtk_color_button_set_alpha( GTK_COLOR_BUTTON(tex_font_colorbt[i]) , + cfg->osd->text.fonts_color[i].alpha ); + tex_font_shadow_togglebt[i] = gtk_toggle_button_new_with_label( _("Shadow") ); + gtk_toggle_button_set_mode( GTK_TOGGLE_BUTTON(tex_font_shadow_togglebt[i]) , FALSE ); + tex_font_shadow_colorbt[i] = gtk_color_button_new(); + gtk_color_button_set_use_alpha( GTK_COLOR_BUTTON(tex_font_shadow_colorbt[i]) , TRUE ); + gcolor.red = cfg->osd->text.fonts_shadow_color[i].red; + gcolor.green = cfg->osd->text.fonts_shadow_color[i].green; + gcolor.blue = cfg->osd->text.fonts_shadow_color[i].blue; + gtk_color_button_set_color( GTK_COLOR_BUTTON(tex_font_shadow_colorbt[i]) , &gcolor ); + gtk_color_button_set_alpha( GTK_COLOR_BUTTON(tex_font_shadow_colorbt[i]) , + cfg->osd->text.fonts_shadow_color[i].alpha ); + gtk_widget_set_sensitive( tex_font_shadow_colorbt[i] , FALSE ); + g_signal_connect( G_OBJECT(tex_font_shadow_togglebt[i]) , "toggled" , + G_CALLBACK(aosd_cb_configure_text_font_shadow_toggle) , + tex_font_shadow_colorbt[i] ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tex_font_shadow_togglebt[i]) , + cfg->osd->text.fonts_draw_shadow[i] ); + gtk_table_attach( GTK_TABLE(tex_font_table) , tex_font_label[i] , + 0 , 1 , i , i + 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + gtk_table_attach( GTK_TABLE(tex_font_table) , tex_font_fontbt[i] , + 1 , 2 , i , i + 1 , GTK_FILL | GTK_EXPAND , GTK_FILL , 0 , 0 ); + gtk_table_attach( GTK_TABLE(tex_font_table) , tex_font_colorbt[i] , + 2 , 3 , i , i + 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + gtk_table_attach( GTK_TABLE(tex_font_table) , tex_font_shadow_togglebt[i] , + 3 , 4 , i , i + 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + gtk_table_attach( GTK_TABLE(tex_font_table) , tex_font_shadow_colorbt[i] , + 4 , 5 , i , i + 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + g_object_set_data( G_OBJECT(tex_font_fontbt[i]) , "fontnum" , GINT_TO_POINTER(i) ); + g_object_set_data( G_OBJECT(tex_font_fontbt[i]) , "color" , tex_font_colorbt[i] ); + g_object_set_data( G_OBJECT(tex_font_fontbt[i]) , "use_shadow" , tex_font_shadow_togglebt[i] ); + g_object_set_data( G_OBJECT(tex_font_fontbt[i]) , "shadow_color" , tex_font_shadow_colorbt[i] ); + aosd_callback_list_add( cb_list , tex_font_fontbt[i] , aosd_cb_configure_text_font_commit ); + } + gtk_container_add( GTK_CONTAINER(tex_font_frame) , tex_font_table ); + gtk_box_pack_start( GTK_BOX(tex_vbox) , tex_font_frame , FALSE , FALSE , 0 ); + + return tex_vbox; +} + + +static void +aosd_ui_configure_decoration_browse ( GtkButton * button , gpointer entry ) +{ + GtkWidget *dialog; + GtkWidget *parent_win = gtk_widget_get_toplevel( GTK_WIDGET(button) ); + dialog = gtk_file_chooser_dialog_new ( _("Select Skin File") , + ( GTK_WIDGET_TOPLEVEL(parent_win) ? GTK_WINDOW(parent_win) : NULL ) , + GTK_FILE_CHOOSER_ACTION_OPEN , + GTK_STOCK_CANCEL , GTK_RESPONSE_CANCEL , + GTK_STOCK_OPEN , GTK_RESPONSE_ACCEPT , NULL ); + if ( gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT ) + { + gchar *filename; + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + gtk_entry_set_text( GTK_ENTRY(entry) , filename ); + g_free( filename ); + } + gtk_widget_destroy( dialog ); + return; +} + + +static void +aosd_cb_configure_decoration_style_commit ( GtkWidget * lv , aosd_cfg_t * cfg ) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(lv) ); + GtkTreeModel *model; + GtkTreeIter iter; + + if ( gtk_tree_selection_get_selected( sel , &model , &iter ) == TRUE ) + { + gint deco_code = 0; + gtk_tree_model_get( model , &iter , 1 , &deco_code , -1 ); + cfg->osd->decoration.code = deco_code; + } + return; +} + + +static void +aosd_cb_configure_decoration_color_commit ( GtkWidget * colorbt , aosd_cfg_t * cfg ) +{ + GdkColor gcolor; + aosd_color_t color; + gint colnum = GPOINTER_TO_INT( g_object_get_data( G_OBJECT(colorbt) , "colnum" ) ); + gtk_color_button_get_color( GTK_COLOR_BUTTON(colorbt) , &gcolor ); + color.red = gcolor.red; + color.green = gcolor.green; + color.blue = gcolor.blue; + color.alpha = gtk_color_button_get_alpha( GTK_COLOR_BUTTON(colorbt) ); + g_array_insert_val( cfg->osd->decoration.colors , colnum , color ); + return; +} + + +static void +aosd_cb_configure_decoration_skinfile_commit ( GtkWidget * entry , aosd_cfg_t * cfg ) +{ + cfg->osd->decoration.skin_file = g_strdup( gtk_entry_get_text(GTK_ENTRY(entry)) ); + return; +} + + +static GtkWidget * +aosd_ui_configure_decoration ( aosd_cfg_t * cfg , GList ** cb_list ) +{ + GtkWidget *dec_hbox; + GtkWidget *dec_rstyle_lv, *dec_rstyle_lv_frame, *dec_rstyle_lv_sw; + GtkListStore *dec_rstyle_store; + GtkCellRenderer *dec_rstyle_lv_rndr_text; + GtkTreeViewColumn *dec_rstyle_lv_col_desc; + GtkTreeSelection *dec_rstyle_lv_sel; + GtkTreeIter iter, iter_sel; + GtkWidget *dec_rstyle_hbox; + GtkWidget *dec_rstyleopts_frame, *dec_rstyleopts_table; + GtkWidget *dec_rstylecustom_frame, *dec_rstylecustom_table; + GtkWidget *dec_rstylecustom_label, *dec_rstylecustom_entry, *dec_rstylecustom_browse_bt; + gint *deco_code_array, deco_code_array_size; + gint colors_max_num = 0, i = 0; + + dec_hbox = gtk_hbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(dec_hbox) , 6 ); + + /* decoration style model + --------------------------------------------- + G_TYPE_STRING -> decoration description + G_TYPE_INT -> decoration code + G_TYPE_INT -> number of user-definable colors + --------------------------------------------- + */ + dec_rstyle_store = gtk_list_store_new( 3 , G_TYPE_STRING , G_TYPE_INT , G_TYPE_INT ); + aosd_deco_style_get_codes_array ( &deco_code_array , &deco_code_array_size ); + for ( i = 0 ; i < deco_code_array_size ; i++ ) + { + gint colors_num = aosd_deco_style_get_numcol( deco_code_array[i] ); + if ( colors_num > colors_max_num ) + colors_max_num = colors_num; + gtk_list_store_append( dec_rstyle_store , &iter ); + gtk_list_store_set( dec_rstyle_store , &iter , + 0 , aosd_deco_style_get_desc( deco_code_array[i] ) , + 1 , deco_code_array[i] , 2 , colors_num , -1 ); + if ( deco_code_array[i] == cfg->osd->decoration.code ) + iter_sel = iter; + } + + dec_rstyle_lv_frame = gtk_frame_new( NULL ); + dec_rstyle_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(dec_rstyle_store) ); + g_object_unref( dec_rstyle_store ); + dec_rstyle_lv_sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(dec_rstyle_lv) ); + gtk_tree_selection_set_mode( dec_rstyle_lv_sel , GTK_SELECTION_BROWSE ); + + dec_rstyle_lv_rndr_text = gtk_cell_renderer_text_new(); + dec_rstyle_lv_col_desc = gtk_tree_view_column_new_with_attributes( + _("Render Style") , dec_rstyle_lv_rndr_text , "text" , 0 , NULL ); + gtk_tree_view_append_column( GTK_TREE_VIEW(dec_rstyle_lv), dec_rstyle_lv_col_desc ); + dec_rstyle_lv_sw = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(dec_rstyle_lv_sw) , + GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); + gtk_container_add( GTK_CONTAINER(dec_rstyle_lv_sw) , dec_rstyle_lv ); + gtk_container_add( GTK_CONTAINER(dec_rstyle_lv_frame) , dec_rstyle_lv_sw ); + + gtk_tree_selection_select_iter( dec_rstyle_lv_sel , &iter_sel ); + gtk_box_pack_start( GTK_BOX(dec_hbox) , dec_rstyle_lv_frame , FALSE , FALSE , 0 ); + aosd_callback_list_add( cb_list , dec_rstyle_lv , aosd_cb_configure_decoration_style_commit ); + + dec_rstyle_hbox = gtk_vbox_new( FALSE , 4 ); + gtk_box_pack_start( GTK_BOX(dec_hbox) , dec_rstyle_hbox , TRUE , TRUE , 0 ); + + /* in colors_max_num now there's the maximum number of colors used by decoration styles */ + dec_rstyleopts_frame = gtk_frame_new( _("Colors") ); + dec_rstyleopts_table = gtk_table_new( (colors_max_num / 3) + 1 , 3 , TRUE ); + gtk_container_set_border_width( GTK_CONTAINER(dec_rstyleopts_table) , 6 ); + gtk_table_set_row_spacings( GTK_TABLE(dec_rstyleopts_table) , 4 ); + gtk_table_set_col_spacings( GTK_TABLE(dec_rstyleopts_table) , 8 ); + gtk_container_add( GTK_CONTAINER(dec_rstyleopts_frame) , dec_rstyleopts_table ); + for ( i = 0 ; i < colors_max_num ; i++ ) + { + GtkWidget *colorbt, *hbox, *label; + aosd_color_t color = g_array_index( cfg->osd->decoration.colors , aosd_color_t , i ); + GdkColor gcolor = { 0 , 0 , 0 , 0 }; + gchar *label_str = NULL; + hbox = gtk_hbox_new( FALSE , 4 ); + label_str = g_strdup_printf( "Color %i:" , i+1 ); + label = gtk_label_new( label_str ); + g_free( label_str ); + colorbt = gtk_color_button_new(); + gtk_color_button_set_use_alpha( GTK_COLOR_BUTTON(colorbt) , TRUE ); + gcolor.red = color.red; gcolor.green = color.green; gcolor.blue = color.blue; + gtk_color_button_set_color( GTK_COLOR_BUTTON(colorbt) , &gcolor ); + gtk_color_button_set_alpha( GTK_COLOR_BUTTON(colorbt) , color.alpha ); + gtk_box_pack_start( GTK_BOX(hbox) , label , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(hbox) , colorbt , FALSE , FALSE , 0 ); + gtk_table_attach( GTK_TABLE(dec_rstyleopts_table) , hbox , + (i % 3) , (i % 3) + 1 , (i / 3) , (i / 3) + 1 , + GTK_FILL , GTK_FILL , 0 , 0 ); + g_object_set_data( G_OBJECT(colorbt) , "colnum" , GINT_TO_POINTER(i) ); + aosd_callback_list_add( cb_list , colorbt , aosd_cb_configure_decoration_color_commit ); + } + gtk_box_pack_start( GTK_BOX(dec_rstyle_hbox) , dec_rstyleopts_frame , FALSE , FALSE , 0 ); + +#if 0 + /* custom skin entry TODO still working on this */ + dec_rstylecustom_frame = gtk_frame_new( _("Custom Skin") ); + dec_rstylecustom_table = gtk_table_new( 1 , 3 , FALSE ); + gtk_container_set_border_width( GTK_CONTAINER(dec_rstylecustom_table) , 6 ); + gtk_table_set_row_spacings( GTK_TABLE(dec_rstylecustom_table) , 4 ); + gtk_table_set_col_spacings( GTK_TABLE(dec_rstylecustom_table) , 4 ); + gtk_container_add( GTK_CONTAINER(dec_rstylecustom_frame) , dec_rstylecustom_table ); + dec_rstylecustom_label = gtk_label_new( _("Skin file:") ); + dec_rstylecustom_entry = gtk_entry_new(); + gtk_entry_set_text( GTK_ENTRY(dec_rstylecustom_entry) , cfg->osd->decoration.skin_file ); + dec_rstylecustom_browse_bt = gtk_button_new_with_label( _("Browse") ); + g_signal_connect( G_OBJECT(dec_rstylecustom_browse_bt) , "clicked" , + G_CALLBACK(aosd_ui_configure_decoration_browse) , dec_rstylecustom_entry ); + gtk_table_attach( GTK_TABLE(dec_rstylecustom_table) , dec_rstylecustom_label , + 0 , 1 , 0 , 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + gtk_table_attach( GTK_TABLE(dec_rstylecustom_table) , dec_rstylecustom_entry , + 1 , 2 , 0 , 1 , GTK_FILL | GTK_EXPAND , GTK_FILL , 0 , 0 ); + gtk_table_attach( GTK_TABLE(dec_rstylecustom_table) , dec_rstylecustom_browse_bt , + 2 , 3 , 0 , 1 , GTK_FILL , GTK_FILL , 0 , 0 ); + aosd_callback_list_add( cb_list , dec_rstylecustom_entry , aosd_cb_configure_decoration_skinfile_commit ); + + gtk_box_pack_start( GTK_BOX(dec_rstyle_hbox) , dec_rstylecustom_frame , FALSE , FALSE , 0 ); +#endif + + return dec_hbox; +} + + +static GtkWidget * +aosd_ui_configure_trigger ( aosd_cfg_t * cfg , GList ** cb_list ) +{ + GtkWidget *tri_hbox; + GtkWidget *tri_event_lv, *tri_event_lv_frame, *tri_event_lv_sw; + GtkListStore *tri_event_store; + GtkCellRenderer *tri_event_lv_rndr_text; + GtkTreeViewColumn *tri_event_lv_col_desc; + GtkTreeSelection *tri_event_lv_sel; + GtkTreeIter iter; + GtkWidget *tri_event_label; + + tri_hbox = gtk_hbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(tri_hbox) , 6 ); + + /* TODO this part will probably be changed in future! */ + + /* event model + --------------------------------------------- + G_TYPE_STRING -> decoration description + --------------------------------------------- + */ + tri_event_store = gtk_list_store_new( 1 , G_TYPE_STRING ); + gtk_list_store_append( tri_event_store , &iter ); + gtk_list_store_set( tri_event_store , &iter , 0 , _("Song Change") , -1 ); + + tri_event_lv_frame = gtk_frame_new( NULL ); + tri_event_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(tri_event_store) ); + g_object_unref( tri_event_store ); + tri_event_lv_sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(tri_event_lv) ); + gtk_tree_selection_set_mode( tri_event_lv_sel , GTK_SELECTION_BROWSE ); + + tri_event_lv_rndr_text = gtk_cell_renderer_text_new(); + tri_event_lv_col_desc = gtk_tree_view_column_new_with_attributes( + _("Event") , tri_event_lv_rndr_text , "text" , 0 , NULL ); + gtk_tree_view_append_column( GTK_TREE_VIEW(tri_event_lv), tri_event_lv_col_desc ); + tri_event_lv_sw = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tri_event_lv_sw) , + GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); + gtk_container_add( GTK_CONTAINER(tri_event_lv_sw) , tri_event_lv ); + gtk_container_add( GTK_CONTAINER(tri_event_lv_frame) , tri_event_lv_sw ); + gtk_tree_selection_select_iter( tri_event_lv_sel , &iter ); + + gtk_box_pack_start( GTK_BOX(tri_hbox) , tri_event_lv_frame , FALSE , FALSE , 0 ); + + tri_event_label = gtk_label_new( _("Song Change is currently the only event that triggers " + "the OSD. Other events will be added in next Audacious OSD versions.") ); + gtk_label_set_line_wrap( GTK_LABEL(tri_event_label) , TRUE ); + gtk_misc_set_alignment( GTK_MISC(tri_event_label) , 0.5 , 0.0 ); + gtk_box_pack_start( GTK_BOX(tri_hbox) , tri_event_label , FALSE , FALSE , 0 ); + + return tri_hbox; +} + + +static void +aosd_cb_configure_test ( gpointer cfg_win ) +{ + gchar *markup_message = NULL; + aosd_cfg_t *cfg = aosd_cfg_new(); + GList *cb_list = g_object_get_data( G_OBJECT(cfg_win) , "cblist" ); + aosd_callback_list_run( cb_list , cfg ); + cfg->set = TRUE; +#ifdef DEBUG + aosd_cfg_debug( cfg ); +#endif + markup_message = g_markup_printf_escaped( + "<span font_desc='%s'>Audacious OSD</span>" , cfg->osd->text.fonts_name[0] ); + aosd_display( markup_message , cfg->osd , TRUE ); + g_free( markup_message ); + aosd_cfg_delete( cfg ); + return; +} + + +static void +aosd_cb_configure_cancel ( gpointer cfg_win ) +{ + GList *cb_list = g_object_get_data( G_OBJECT(cfg_win) , "cblist" ); + aosd_callback_list_free( cb_list ); + aosd_shutdown(); /* stop any displayed osd */ + gtk_widget_destroy( GTK_WIDGET(cfg_win) ); + return; +} + + +static void +aosd_cb_configure_ok ( gpointer cfg_win ) +{ + gchar *markup_message = NULL; + aosd_cfg_t *cfg = aosd_cfg_new(); + GList *cb_list = g_object_get_data( G_OBJECT(cfg_win) , "cblist" ); + aosd_callback_list_run( cb_list , cfg ); + cfg->set = TRUE; + aosd_shutdown(); /* stop any displayed osd */ + if ( global_config != NULL ) + { + /* plugin is active */ + aosd_cfg_delete( global_config ); /* delete old global_config */ + global_config = cfg; /* put the new one */ + aosd_cfg_save( cfg ); /* save the new configuration on config file */ + } + else + { + /* plugin is not active */ + aosd_cfg_save( cfg ); /* save the new configuration on config file */ + } + aosd_callback_list_free( cb_list ); + gtk_widget_destroy( GTK_WIDGET(cfg_win) ); + return; +} + + +void +aosd_ui_configure ( aosd_cfg_t * cfg ) +{ + static GtkWidget *cfg_win = NULL; + GtkWidget *cfg_vbox; + GtkWidget *cfg_nb; + GtkWidget *cfg_bbar_hbbox; + GtkWidget *cfg_bbar_bt_ok, *cfg_bbar_bt_test, *cfg_bbar_bt_cancel; + GtkWidget *cfg_position_widget; + GtkWidget *cfg_animation_widget; + GtkWidget *cfg_text_widget; + GtkWidget *cfg_decoration_widget; + GtkWidget *cfg_trigger_widget; + GdkGeometry cfg_win_hints; + GList *cb_list = NULL; /* list of custom callbacks */ + + if ( cfg_win != NULL ) + { + gtk_window_present( GTK_WINDOW(cfg_win) ); + return; + } + + cfg_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(cfg_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_title( GTK_WINDOW(cfg_win) , _("Audacious OSD - configuration") ); + gtk_container_set_border_width( GTK_CONTAINER(cfg_win), 10 ); + g_signal_connect( G_OBJECT(cfg_win) , "destroy" , + G_CALLBACK(gtk_widget_destroyed) , &cfg_win ); + cfg_win_hints.min_width = -1; + cfg_win_hints.min_height = 350; + gtk_window_set_geometry_hints( GTK_WINDOW(cfg_win) , GTK_WIDGET(cfg_win) , + &cfg_win_hints , GDK_HINT_MIN_SIZE ); + + cfg_vbox = gtk_vbox_new( 0 , FALSE ); + gtk_container_add( GTK_CONTAINER(cfg_win) , cfg_vbox ); + + cfg_nb = gtk_notebook_new(); + gtk_notebook_set_tab_pos( GTK_NOTEBOOK(cfg_nb) , GTK_POS_TOP ); + gtk_box_pack_start( GTK_BOX(cfg_vbox) , cfg_nb , TRUE , TRUE , 0 ); + + gtk_box_pack_start( GTK_BOX(cfg_vbox) , gtk_hseparator_new() , FALSE , FALSE , 4 ); + + cfg_bbar_hbbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(cfg_bbar_hbbox) , GTK_BUTTONBOX_START ); + gtk_box_pack_start( GTK_BOX(cfg_vbox) , cfg_bbar_hbbox , FALSE , FALSE , 0 ); + cfg_bbar_bt_test = gtk_button_new_with_label( _("Test") ); + gtk_button_set_image( GTK_BUTTON(cfg_bbar_bt_test) , + gtk_image_new_from_stock( GTK_STOCK_MEDIA_PLAY , GTK_ICON_SIZE_BUTTON ) ); + gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_test ); + gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(cfg_bbar_hbbox) , cfg_bbar_bt_test , FALSE ); + cfg_bbar_bt_cancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL ); + gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_cancel ); + gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(cfg_bbar_hbbox) , cfg_bbar_bt_cancel , TRUE ); + cfg_bbar_bt_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); + gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_ok ); + gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(cfg_bbar_hbbox) , cfg_bbar_bt_ok , TRUE ); + + /* add POSITION page */ + cfg_position_widget = aosd_ui_configure_position( cfg , &cb_list ); + gtk_notebook_append_page( GTK_NOTEBOOK(cfg_nb) , + cfg_position_widget , gtk_label_new( _("Position") ) ); + + /* add ANIMATION page */ + cfg_animation_widget = aosd_ui_configure_animation( cfg , &cb_list ); + gtk_notebook_append_page( GTK_NOTEBOOK(cfg_nb) , + cfg_animation_widget , gtk_label_new( _("Animation") ) ); + + /* add TEXT page */ + cfg_text_widget = aosd_ui_configure_text( cfg , &cb_list ); + gtk_notebook_append_page( GTK_NOTEBOOK(cfg_nb) , + cfg_text_widget , gtk_label_new( _("Text") ) ); + + /* add DECORATION page */ + cfg_decoration_widget = aosd_ui_configure_decoration( cfg , &cb_list ); + gtk_notebook_append_page( GTK_NOTEBOOK(cfg_nb) , + cfg_decoration_widget , gtk_label_new( _("Decoration") ) ); + + /* add TRIGGER page */ + cfg_trigger_widget = aosd_ui_configure_trigger( cfg , &cb_list ); + gtk_notebook_append_page( GTK_NOTEBOOK(cfg_nb) , + cfg_trigger_widget , gtk_label_new( _("Trigger") ) ); + + g_object_set_data( G_OBJECT(cfg_win) , "cblist" , cb_list ); + + g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_test) , "clicked" , + G_CALLBACK(aosd_cb_configure_test) , cfg_win ); + g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_cancel) , "clicked" , + G_CALLBACK(aosd_cb_configure_cancel) , cfg_win ); + g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_ok) , "clicked" , + G_CALLBACK(aosd_cb_configure_ok) , cfg_win ); + + gtk_widget_show_all( cfg_win ); +} + + +/* about box */ +void +aosd_ui_about ( void ) +{ + static GtkWidget *about_win = NULL; + GtkWidget *about_vbox; + GtkWidget *logoandinfo_vbox; + GtkWidget *info_tv, *info_tv_sw, *info_tv_frame; + GtkWidget *bbar_bbox, *bbar_bt_ok; + GtkTextBuffer *info_tb; + GdkGeometry abount_win_hints; + + if ( about_win != NULL ) + { + gtk_window_present( GTK_WINDOW(about_win) ); + return; + } + + about_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(about_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_position( GTK_WINDOW(about_win), GTK_WIN_POS_CENTER ); + gtk_window_set_title( GTK_WINDOW(about_win), _("Audacious OSD - about") ); + abount_win_hints.min_width = 420; + abount_win_hints.min_height = 240; + gtk_window_set_geometry_hints( GTK_WINDOW(about_win) , GTK_WIDGET(about_win) , + &abount_win_hints , GDK_HINT_MIN_SIZE ); + /* gtk_window_set_resizable( GTK_WINDOW(about_win) , FALSE ); */ + gtk_container_set_border_width( GTK_CONTAINER(about_win) , 10 ); + g_signal_connect( G_OBJECT(about_win) , "destroy" , G_CALLBACK(gtk_widget_destroyed) , &about_win ); + + about_vbox = gtk_vbox_new( FALSE , 0 ); + gtk_container_add( GTK_CONTAINER(about_win) , about_vbox ); + + logoandinfo_vbox = gtk_vbox_new( TRUE , 2 ); + + /* TODO make a logo or make someone do it! :) + logo_pixbuf = gdk_pixbuf_new_from_xpm_data( (const gchar **)evdev_plug_logo_xpm ); + logo_image = gtk_image_new_from_pixbuf( logo_pixbuf ); + g_object_unref( logo_pixbuf ); + + logo_frame = gtk_frame_new( NULL ); + gtk_container_add( GTK_CONTAINER(logo_frame) , logo_image ); + gtk_box_pack_start( GTK_BOX(logoandinfo_vbox) , logo_frame , TRUE , TRUE , 0 ); */ + + info_tv = gtk_text_view_new(); + info_tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(info_tv) ); + gtk_text_view_set_editable( GTK_TEXT_VIEW(info_tv) , FALSE ); + gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW(info_tv) , FALSE ); + gtk_text_view_set_justification( GTK_TEXT_VIEW(info_tv) , GTK_JUSTIFY_LEFT ); + gtk_text_view_set_left_margin( GTK_TEXT_VIEW(info_tv) , 10 ); + + gtk_text_buffer_set_text( info_tb , + _("\nAudacious OSD " AOSD_VERSION_PLUGIN + "\nhttp://www.develia.org/projects.php?p=aosd\n" + "written by Giacomo Lozito\n" + "< james@develia.org >\n\n" + "On-Screen-Display is based on Ghosd library\n" + "written by Evan Martin\n" + "http://neugierig.org/software/ghosd/\n\n") , -1 ); + + info_tv_sw = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(info_tv_sw) , + GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); + gtk_container_add( GTK_CONTAINER(info_tv_sw) , info_tv ); + info_tv_frame = gtk_frame_new( NULL ); + gtk_container_add( GTK_CONTAINER(info_tv_frame) , info_tv_sw ); + gtk_box_pack_start( GTK_BOX(logoandinfo_vbox) , info_tv_frame , TRUE , TRUE , 0 ); + + gtk_box_pack_start( GTK_BOX(about_vbox) , logoandinfo_vbox , TRUE , TRUE , 0 ); + + /* horizontal separator and buttons */ + gtk_box_pack_start( GTK_BOX(about_vbox) , gtk_hseparator_new() , FALSE , FALSE , 4 ); + bbar_bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(bbar_bbox) , GTK_BUTTONBOX_END ); + bbar_bt_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); + g_signal_connect_swapped( G_OBJECT(bbar_bt_ok) , "clicked" , + G_CALLBACK(gtk_widget_destroy) , about_win ); + gtk_container_add( GTK_CONTAINER(bbar_bbox) , bbar_bt_ok ); + gtk_box_pack_start( GTK_BOX(about_vbox) , bbar_bbox , FALSE , FALSE , 0 ); + + gtk_widget_show_all( about_win ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_ui.c.old Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,159 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#include "aosd_ui.h" +#include <glib.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> + + +gint +aosd_display_osd ( void ) +{ + GtkWidget *osd_win; + GtkWidget *osd_darea; + PangoLayout *osd_layout; + PangoFontDescription *osd_fontdesc; + GdkPixmap *osd_darea_pixmap, *osd_darea_bitmap; + GdkGC *osd_darea_gc; + GdkColor fg_color, bg_color, bitmap_color; + GdkColormap *bitmap_colormap; + gint max_width = 0, border_width = 1; + gint width = 0, height = 0; + gint off_x = 0, off_y = 0; + PangoAlignment osd_alignment = PANGO_ALIGN_CENTER; + gboolean translucent_bg = TRUE; + + osd_win = gtk_window_new( GTK_WINDOW_POPUP ); + gtk_widget_add_events( osd_win , GDK_ENTER_NOTIFY_MASK ); + gtk_widget_realize( osd_win ); + + osd_darea = gtk_drawing_area_new(); + gtk_container_add( GTK_CONTAINER(osd_win) , osd_darea ); + gtk_widget_show( osd_darea ); + + osd_fontdesc = pango_font_description_from_string("Courier,Mono 28"); + + osd_layout = gtk_widget_create_pango_layout( osd_darea , "AUDACIOUS OSD 0.1 by Giacomo" ); + pango_layout_set_ellipsize( osd_layout , PANGO_ELLIPSIZE_NONE ); + pango_layout_set_justify( osd_layout , FALSE ); + pango_layout_set_alignment( osd_layout , osd_alignment ); + pango_layout_set_font_description( osd_layout , osd_fontdesc ); + + max_width = gdk_screen_get_width( gdk_screen_get_default() ) - 8; + pango_layout_set_width( osd_layout , PANGO_SCALE * max_width ); + pango_layout_get_pixel_size( osd_layout , &width , &height ); + + off_x = border_width * 2; + off_y = border_width * 2; + + if ( osd_alignment == PANGO_ALIGN_CENTER ) + off_x -= max_width/2 - width/2; + else if ( osd_alignment == PANGO_ALIGN_RIGHT ) + off_x -= max_width - width; + + width += border_width * 4; + height += border_width * 4; + + gtk_widget_set_size_request( osd_darea , width , height ); + gtk_widget_realize( osd_darea ); + + osd_darea_pixmap = gdk_pixmap_new( GDK_DRAWABLE(osd_darea->window) , width , height , -1 ); + + osd_darea_gc = gdk_gc_new( GDK_DRAWABLE(osd_darea_pixmap) ); + gdk_gc_copy( osd_darea_gc , osd_darea->style->fg_gc[GTK_STATE_NORMAL] ); + + gdk_color_parse( "Blue" , &fg_color ); /* TODO pass color as function param */ + gdk_color_parse( "White" , &bg_color ); /* TODO pass color as function param */ + + gdk_gc_set_rgb_fg_color( osd_darea_gc , &bg_color ); + gdk_draw_rectangle( GDK_DRAWABLE(osd_darea_pixmap) , osd_darea_gc , TRUE , + 0 , 0 , width , height ); + gdk_gc_set_rgb_fg_color( osd_darea_gc , &fg_color ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_pixmap) , osd_darea_gc , off_x , off_y , osd_layout ); + g_object_unref( osd_darea_gc ); + + osd_darea_bitmap = gdk_pixmap_new( GDK_DRAWABLE(osd_darea->window) , width , height , 1 ); + osd_darea_gc = gdk_gc_new( GDK_DRAWABLE(osd_darea_bitmap) ); + + /* gdk will complain if we don't pass a colormap to osd_darea_gc */ + gdk_gc_set_colormap( osd_darea_gc , gdk_colormap_get_system() ); + + bitmap_color.pixel = 0; + gdk_gc_set_foreground( osd_darea_gc , &bitmap_color ); + + if ( translucent_bg == TRUE ) + { + gint w = 2, h = 2; + GdkPixmap *stipple_bitmap; + + stipple_bitmap = gdk_pixmap_new( NULL , w , h , 1 ); + bitmap_color.pixel = 0; gdk_gc_set_foreground( osd_darea_gc , &bitmap_color ); + gdk_draw_rectangle( GDK_DRAWABLE(stipple_bitmap) , osd_darea_gc , TRUE , 0 , 0 , w , h ); + bitmap_color.pixel = 1; gdk_gc_set_foreground( osd_darea_gc , &bitmap_color ); + gdk_draw_point( GDK_DRAWABLE(stipple_bitmap) , osd_darea_gc , 0 , 0 ); + gdk_draw_point( GDK_DRAWABLE(stipple_bitmap) , osd_darea_gc , 1 , 1 ); + bitmap_color.pixel = 0; gdk_gc_set_foreground( osd_darea_gc , &bitmap_color ); + gdk_draw_rectangle( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , TRUE , + 0 , 0 , width , height ); + gdk_gc_set_stipple( osd_darea_gc , stipple_bitmap ); + gdk_gc_set_fill( osd_darea_gc , GDK_STIPPLED ); + bitmap_color.pixel = 1; gdk_gc_set_foreground( osd_darea_gc , &bitmap_color ); + gdk_draw_rectangle( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , TRUE , + 0 , 0 , width , height ); + gdk_gc_set_fill( osd_darea_gc , GDK_SOLID ); + } + else + gdk_draw_rectangle( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , TRUE , + 0 , 0 , width , height ); + + bitmap_color.pixel = 1; + gdk_gc_set_foreground( osd_darea_gc , &bitmap_color ); + + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x , off_y , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x + border_width , off_y , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x + border_width , off_y + border_width , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x , off_y + border_width , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x - border_width , off_y + border_width , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x - border_width , off_y , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x - border_width , off_y - border_width , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x , off_y - border_width , osd_layout ); + gdk_draw_layout( GDK_DRAWABLE(osd_darea_bitmap) , osd_darea_gc , + off_x + border_width , off_y - border_width , osd_layout ); + + g_object_unref( osd_darea_gc ); + + gdk_window_set_back_pixmap( GDK_WINDOW(osd_darea->window) , osd_darea_pixmap , FALSE ); + gdk_window_shape_combine_mask( GDK_WINDOW(osd_win->window) , osd_darea_bitmap , 0 , 0 ); + + gtk_widget_show( osd_win ); + + pango_font_description_free( osd_fontdesc ); + g_object_unref( osd_layout ); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/aosd_ui.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,32 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 +* +* 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., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef _I_AOSD_UI_H +#define _I_AOSD_UI_H 1 + +#include "aosd_common.h" +#include "aosd_cfg.h" +#include <glib.h> + + +void aosd_ui_configure ( aosd_cfg_t * ); +void aosd_ui_about ( void ); + +#endif /* !_I_AOSD_UI_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd-internal.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,25 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#include <X11/Xlib.h> + +#include "ghosd.h" + +typedef struct { + GhosdRenderFunc func; + void *data; + void (*data_destroy)(void*); +} RenderCallback; + +struct _Ghosd { + Display *dpy; + Window win; + int transparent; + int x, y, width, height; + + Pixmap background; + RenderCallback render; +}; + +/* vim: set ts=2 sw=2 et cino=(0 : */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd-license Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,20 @@ +Copyright (c) 2006 Evan Martin <martine@danga.com> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd-main.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,171 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "ghosd.h" +#include "ghosd-internal.h" + +static void +ghosd_main_iteration(Ghosd *ghosd) { + XEvent ev, pev; + XNextEvent(ghosd->dpy, &ev); + + /* smash multiple configure/exposes into one. */ + if (ev.type == ConfigureNotify) { + while (XPending(ghosd->dpy)) { + XPeekEvent(ghosd->dpy, &pev); + if (pev.type != ConfigureNotify && pev.type != Expose) + break; + XNextEvent(ghosd->dpy, &ev); + } + } + + switch (ev.type) { + case Expose: + break; + case ConfigureNotify: + if (ghosd->width > 0) { + /* XXX if the window manager disagrees with our positioning here, + * we loop. */ + if (ghosd->x != ev.xconfigure.x || + ghosd->y != ev.xconfigure.y) { + /*width = ev.xconfigure.width; + height = ev.xconfigure.height;*/ + XMoveResizeWindow(ghosd->dpy, ghosd->win, + ghosd->x, ghosd->y, ghosd->width, ghosd->height); + } + } + break; + } +} + +void +ghosd_main_iterations(Ghosd *ghosd) { + while (XPending(ghosd->dpy)) + ghosd_main_iteration(ghosd); +} + +void +ghosd_main_until(Ghosd *ghosd, struct timeval *until) { + struct timeval tv_now; + + ghosd_main_iterations(ghosd); + + for (;;) { + gettimeofday(&tv_now, NULL); + int dt = (until->tv_sec - tv_now.tv_sec )*1000 + + (until->tv_usec - tv_now.tv_usec)/1000; + if (dt <= 0) break; + + struct pollfd pollfd = { ghosd_get_socket(ghosd), POLLIN, 0 }; + int ret = poll(&pollfd, 1, dt); + if (ret < 0) { + perror("poll"); + exit(1); + } else if (ret > 0) { + ghosd_main_iterations(ghosd); + } else { + /* timer expired. */ + break; + } + } +} + +typedef struct { + cairo_surface_t* surface; + float alpha; + RenderCallback user_render; +} GhosdFlashData; + +static void +flash_render(Ghosd *ghosd, cairo_t *cr, void* data) { + GhosdFlashData *flash = data; + + /* the first time we render, let the client render into their own surface. */ + if (flash->surface == NULL) { + cairo_t *rendered_cr; + flash->surface = cairo_surface_create_similar(cairo_get_target(cr), + CAIRO_CONTENT_COLOR_ALPHA, + ghosd->width, ghosd->height); + rendered_cr = cairo_create(flash->surface); + flash->user_render.func(ghosd, rendered_cr, flash->user_render.data); + cairo_destroy(rendered_cr); + } + + /* now that we have a rendered surface, all we normally do is copy that to + * the screen. */ + cairo_set_source_surface(cr, flash->surface, 0, 0); + cairo_paint_with_alpha(cr, flash->alpha); +} + +/* we don't need to free the flashdata object, because we stack-allocate that. + * but we do need to let the old user data free itself... */ +static void +flash_destroy(void *data) { + GhosdFlashData *flash = data; + if (flash->user_render.data_destroy) + flash->user_render.data_destroy(flash->user_render.data); +} + +void +ghosd_flash(Ghosd *ghosd, int fade_ms, int total_display_ms) { + GhosdFlashData flash = {0}; + memcpy(&flash.user_render, &ghosd->render, sizeof(RenderCallback)); + ghosd_set_render(ghosd, flash_render, &flash, flash_destroy); + + ghosd_show(ghosd); + + const int STEP_MS = 50; + const float dalpha = 1.0 / (fade_ms / (float)STEP_MS); + struct timeval tv_nextupdate; + + /* fade in. */ + for (flash.alpha = 0; flash.alpha < 1.0; flash.alpha += dalpha) { + if (flash.alpha > 1.0) flash.alpha = 1.0; + ghosd_render(ghosd); + + gettimeofday(&tv_nextupdate, NULL); + tv_nextupdate.tv_usec += STEP_MS*1000; + ghosd_main_until(ghosd, &tv_nextupdate); + } + + /* full display. */ + flash.alpha = 1.0; + ghosd_render(ghosd); + + gettimeofday(&tv_nextupdate, NULL); + tv_nextupdate.tv_usec += (total_display_ms - (2*fade_ms))*1000; + ghosd_main_until(ghosd, &tv_nextupdate); + + /* fade out. */ + for (flash.alpha = 1.0; flash.alpha > 0.0; flash.alpha -= dalpha) { + ghosd_render(ghosd); + + gettimeofday(&tv_nextupdate, NULL); + tv_nextupdate.tv_usec += STEP_MS*1000; + ghosd_main_until(ghosd, &tv_nextupdate); + } + + flash.alpha = 0; + ghosd_render(ghosd); + + /* display for another half-second, + * because otherwise the fade out attracts your eye + * and then you'll see a flash while it repaints where the ghosd was. + */ + gettimeofday(&tv_nextupdate, NULL); + tv_nextupdate.tv_usec += 500*1000; + ghosd_main_until(ghosd, &tv_nextupdate); +} + +/* vim: set ts=2 sw=2 et cino=(0 : */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd-text.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,53 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#include "config.h" + +#include <pango/pangocairo.h> +#include "ghosd-internal.h" +#include "ghosd-text.h" + +static void +render_text(Ghosd *ghosd, cairo_t *cr, void* data) { + PangoLayout *layout = data; + + /* drop shadow! */ + cairo_set_source_rgba(cr, 0, 0, 0, 0.8); + cairo_move_to(cr, 4, 4); + pango_cairo_show_layout(cr, layout); + + /* and the actual text. */ + cairo_set_source_rgba(cr, 1, 1, 1, 1.0); + cairo_move_to(cr, 0, 0); + pango_cairo_show_layout(cr, layout); +} + +Ghosd* +ghosd_text_new(const char *markup, int x, int y) { + Ghosd *ghosd; + PangoContext *context; + PangoLayout *layout; + PangoRectangle ink_rect; + + g_type_init(); + + context = pango_cairo_font_map_create_context( + PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default())); + layout = pango_layout_new(context); + + pango_layout_set_markup(layout, markup, -1); + + pango_layout_get_pixel_extents(layout, &ink_rect, NULL); + + const int width = ink_rect.x + ink_rect.width+5; + const int height = ink_rect.y + ink_rect.height+5; + + ghosd = ghosd_new(); + ghosd_set_position(ghosd, x, y, width, height); + ghosd_set_render(ghosd, render_text, layout, g_object_unref); + + return ghosd; +} + +/* vim: set ts=2 sw=2 et cino=(0 : */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd-text.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,14 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#ifndef __GHOSD_TEXT_H__ +#define __GHOSD_TEXT_H__ + +#include <pango/pango-layout.h> + +Ghosd* ghosd_text_new(const char *markup, int x, int y); + +#endif /* __GHOSD_TEXT_H__ */ + +/* vim: set ts=2 sw=2 et cino=(0 : */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd.c Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,248 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <cairo/cairo-xlib-xrender.h> +#include <X11/Xatom.h> + +#include "ghosd.h" +#include "ghosd-internal.h" + +static Pixmap +take_snapshot(Ghosd *ghosd) { + Pixmap pixmap; + GC gc; + + /* create a pixmap to hold the screenshot. */ + pixmap = XCreatePixmap(ghosd->dpy, ghosd->win, + ghosd->width, ghosd->height, + DefaultDepth(ghosd->dpy, DefaultScreen(ghosd->dpy))); + + /* then copy the screen into the pixmap. */ + gc = XCreateGC(ghosd->dpy, pixmap, 0, NULL); + XSetSubwindowMode(ghosd->dpy, gc, IncludeInferiors); + XCopyArea(ghosd->dpy, DefaultRootWindow(ghosd->dpy), pixmap, gc, + ghosd->x, ghosd->y, ghosd->width, ghosd->height, + 0, 0); + XSetSubwindowMode(ghosd->dpy, gc, ClipByChildren); + XFreeGC(ghosd->dpy, gc); + + return pixmap; +} + +void +ghosd_render(Ghosd *ghosd) { + Pixmap pixmap; + GC gc; + + /* make our own copy of the background pixmap as the initial surface. */ + pixmap = XCreatePixmap(ghosd->dpy, ghosd->win, ghosd->width, ghosd->height, + DefaultDepth(ghosd->dpy, DefaultScreen(ghosd->dpy))); + + gc = XCreateGC(ghosd->dpy, pixmap, 0, NULL); + if (ghosd->transparent) { + XCopyArea(ghosd->dpy, ghosd->background, pixmap, gc, + 0, 0, ghosd->width, ghosd->height, 0, 0); + } else { + XFillRectangle(ghosd->dpy, pixmap, gc, + 0, 0, ghosd->width, ghosd->height); + } + XFreeGC(ghosd->dpy, gc); + + /* render with cairo. */ + if (ghosd->render.func) { + /* create cairo surface using the pixmap. */ + XRenderPictFormat *xrformat = + XRenderFindVisualFormat(ghosd->dpy, + DefaultVisual(ghosd->dpy, + DefaultScreen(ghosd->dpy))); + cairo_surface_t *surf = + cairo_xlib_surface_create_with_xrender_format( + ghosd->dpy, pixmap, + ScreenOfDisplay(ghosd->dpy, DefaultScreen(ghosd->dpy)), + xrformat, + ghosd->width, ghosd->height); + + /* draw some stuff. */ + cairo_t *cr = cairo_create(surf); + ghosd->render.func(ghosd, cr, ghosd->render.data); + cairo_destroy(cr); + } + + /* point window at its new backing pixmap. */ + XSetWindowBackgroundPixmap(ghosd->dpy, ghosd->win, pixmap); + /* I think it's ok to free it here because XCreatePixmap(3X11) says: "the X + * server frees the pixmap storage when there are no references to it". + */ + XFreePixmap(ghosd->dpy, pixmap); + + /* and tell the window to redraw with this pixmap. */ + XClearWindow(ghosd->dpy, ghosd->win); +} + +static void +set_hints(Display *dpy, Window win) { + /* we're almost a _NET_WM_WINDOW_TYPE_SPLASH, but we don't want + * to be centered on the screen. instead, manually request the + * behavior we want. */ + + /* turn off window decorations. + * we could pull this in from a motif header, but it's easier to + * use this snippet i found on a mailing list. */ + Atom mwm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); +#define MWM_HINTS_DECORATIONS (1<<1) + struct { + long flags, functions, decorations, input_mode; + } mwm_hints_setting = { + MWM_HINTS_DECORATIONS, 0, 0, 0 + }; + XChangeProperty(dpy, win, + mwm_hints, mwm_hints, 32, PropModeReplace, + (unsigned char *)&mwm_hints_setting, 4); + + /* always on top, not in taskbar or pager. */ + Atom win_state = XInternAtom(dpy, "_NET_WM_STATE", False); + Atom win_state_setting[] = { + XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False), + XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False), + XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False) + }; + XChangeProperty(dpy, win, win_state, XA_ATOM, 32, + PropModeReplace, (unsigned char*)&win_state_setting, 3); +} + +static Window +make_window(Display *dpy) { + Window win; + XSetWindowAttributes att; + + /* XXX I don't understand X well enough to know if these are the correct + * settings. */ + att.backing_store = WhenMapped; + att.background_pixel = None; + att.border_pixel = 0; + att.background_pixmap = None; + att.save_under = True; + att.event_mask = ExposureMask | StructureNotifyMask; + att.override_redirect = True; + + win = XCreateWindow(dpy, DefaultRootWindow(dpy), + -1, -1, 1, 1, 0, + CopyFromParent, InputOutput, CopyFromParent, + CWBackingStore | CWBackPixel | CWBackPixmap | + CWEventMask | CWSaveUnder | CWOverrideRedirect, + &att); + + set_hints(dpy, win); + + /* XXX: XSetClassHint? */ + + return win; +} + +void +ghosd_show(Ghosd *ghosd) { + if (ghosd->transparent) { + if (ghosd->background) + XFreePixmap(ghosd->dpy, ghosd->background); + ghosd->background = take_snapshot(ghosd); + } + + ghosd_render(ghosd); + + XMapWindow(ghosd->dpy, ghosd->win); +} + +void +ghosd_hide(Ghosd *ghosd) { + XUnmapWindow(ghosd->dpy, ghosd->win); +} + +void +ghosd_set_transparent(Ghosd *ghosd, int transparent) { + ghosd->transparent = (transparent != 0); +} + +void +ghosd_set_render(Ghosd *ghosd, GhosdRenderFunc render_func, + void *user_data, void (*user_data_d)(void*)) { + ghosd->render.func = render_func; + ghosd->render.data = user_data; + ghosd->render.data_destroy = user_data_d; +} + +void +ghosd_set_position(Ghosd *ghosd, int x, int y, int width, int height) { + const int dpy_width = DisplayWidth(ghosd->dpy, DefaultScreen(ghosd->dpy)); + const int dpy_height = DisplayHeight(ghosd->dpy, DefaultScreen(ghosd->dpy)); + + if (x == GHOSD_COORD_CENTER) { + x = (dpy_width - width) / 2; + } else if (x < 0) { + x = dpy_width - width + x; + } + + if (y == GHOSD_COORD_CENTER) { + y = (dpy_height - height) / 2; + } else if (y < 0) { + y = dpy_height - height + y; + } + + ghosd->x = x; + ghosd->y = y; + ghosd->width = width; + ghosd->height = height; + + XMoveResizeWindow(ghosd->dpy, ghosd->win, + ghosd->x, ghosd->y, ghosd->width, ghosd->height); +} + +#if 0 +static int +x_error_handler(Display *dpy, XErrorEvent* evt) { + /* segfault so we can get a backtrace. */ + char *x = NULL; + *x = 0; + return 0; +} +#endif + +Ghosd* +ghosd_new(void) { + Ghosd *ghosd; + Display *dpy; + Window win; + + dpy = XOpenDisplay(NULL); + if (dpy == NULL) { + fprintf(stderr, "Couldn't open display: (XXX FIXME)\n"); + return NULL; + } + + win = make_window(dpy); + + ghosd = calloc(1, sizeof(Ghosd)); + ghosd->dpy = dpy; + ghosd->win = win; + ghosd->transparent = 1; + + return ghosd; +} + +void +ghosd_destroy(Ghosd* ghosd) { + if (ghosd->background) + XFreePixmap(ghosd->dpy, ghosd->background); + XDestroyWindow(ghosd->dpy, ghosd->win); +} + +int +ghosd_get_socket(Ghosd *ghosd) { + return ConnectionNumber(ghosd->dpy); +} + +/* vim: set ts=2 sw=2 et cino=(0 : */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aosd/ghosd.h Mon Jan 29 06:40:04 2007 -0800 @@ -0,0 +1,38 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#ifndef __GHOSD_H__ +#define __GHOSD_H__ + +#include <cairo/cairo.h> + +#include <values.h> /* MAXINT */ +#include <sys/time.h> /* timeval */ + +typedef struct _Ghosd Ghosd; + +typedef void (*GhosdRenderFunc)(Ghosd *ghosd, cairo_t *cr, void *user_data); + +Ghosd *ghosd_new(void); +void ghosd_destroy(Ghosd* ghosd); + +#define GHOSD_COORD_CENTER MAXINT +void ghosd_set_transparent(Ghosd *ghosd, int transparent); +void ghosd_set_position(Ghosd *ghosd, int x, int y, int width, int height); +void ghosd_set_render(Ghosd *ghosd, GhosdRenderFunc render_func, + void* user_data, void (*user_data_d)(void*)); + +void ghosd_render(Ghosd *ghosd); +void ghosd_show(Ghosd *ghosd); +void ghosd_hide(Ghosd *ghosd); + +void ghosd_main_iterations(Ghosd *ghosd); +void ghosd_main_until(Ghosd *ghosd, struct timeval *until); +void ghosd_flash(Ghosd *ghosd, int fade_ms, int total_display_ms); + +int ghosd_get_socket(Ghosd *ghosd); + +#endif /* __GHOSD_H__ */ + +/* vim: set ts=2 sw=2 et cino=(0 : */