Mercurial > audlegacy-plugins
changeset 2631:887b2c5a1fbb
Branch merge
author | Ralf Ertzinger <ralf@skytale.net> |
---|---|
date | Thu, 22 May 2008 19:32:39 +0200 |
parents | 76924684ee4f (current diff) 2ce9e17525dc (diff) |
children | 55bc7318ff40 |
files | src/alsa/init.c src/neon/neon.c src/scrobbler/md5.c src/scrobbler/md5.h src/sid/xs_md5.c src/sid/xs_md5.h |
diffstat | 184 files changed, 22474 insertions(+), 1180 deletions(-) [+] |
line wrap: on
line diff
--- a/po/Makevars Thu May 22 19:31:48 2008 +0200 +++ b/po/Makevars Thu May 22 19:32:39 2008 +0200 @@ -16,7 +16,7 @@ # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = -MSGID_BUGS_ADDRESS = http://bugs.audacious-media-player.org +MSGID_BUGS_ADDRESS = http://bugzilla.atheme.org/ build: all
--- a/po/update-potfiles.sh Thu May 22 19:31:48 2008 +0200 +++ b/po/update-potfiles.sh Thu May 22 19:32:39 2008 +0200 @@ -2,4 +2,4 @@ rm POTFILES* echo "# Please don't update this file manually - use ./update-potfiles.sh instead!" > POTFILES.in cd .. -find src/ \( -name "*.c*" -o -name "*.glade" \) -exec grep -lE "translatable|_\(" \{\} \; | sort | uniq >> po/POTFILES.in +find src/ \( -name "*.c" -o -name "*.cxx" -o -name "*.cc" -o -name "*.glade" \) -exec grep -lE "translatable|_\(" \{\} \; | sort | uniq >> po/POTFILES.in
--- a/src/CoreAudio/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/CoreAudio/about.c Thu May 22 19:32:39 2008 +0200 @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "coreaudio.h" -#include <audacious/util.h> void osx_about(void) {
--- a/src/CoreAudio/audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/CoreAudio/audio.c Thu May 22 19:32:39 2008 +0200 @@ -18,7 +18,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "coreaudio.h" -#include <audacious/util.h> #include <errno.h> #include <CoreAudio/CoreAudio.h>
--- a/src/OSS/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/OSS/about.c Thu May 22 19:32:39 2008 +0200 @@ -25,7 +25,6 @@ #include <audacious/i18n.h> #include <gtk/gtk.h> -#include <audacious/util.h> void
--- a/src/OSS/audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/OSS/audio.c Thu May 22 19:32:39 2008 +0200 @@ -22,7 +22,6 @@ extern void close_mixer_device(); #include <glib.h> -#include <audacious/util.h> #include <string.h> #include <unistd.h>
--- a/src/OSS4/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/OSS4/about.c Thu May 22 19:32:39 2008 +0200 @@ -28,7 +28,6 @@ #include <audacious/i18n.h> #include <gtk/gtk.h> -#include <audacious/util.h> void
--- a/src/OSS4/audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/OSS4/audio.c Thu May 22 19:32:39 2008 +0200 @@ -22,7 +22,6 @@ extern void close_mixer_device(); #include <glib.h> -#include <audacious/util.h> #include <string.h> #include <unistd.h>
--- a/src/aac/libmp4.c Thu May 22 19:31:48 2008 +0200 +++ b/src/aac/libmp4.c Thu May 22 19:32:39 2008 +0200 @@ -8,9 +8,7 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include <audacious/i18n.h> -#include <audacious/strings.h> #define MP4_VERSION VERSION #define SBR_DEC
--- a/src/aac/mp4_utils.c Thu May 22 19:31:48 2008 +0200 +++ b/src/aac/mp4_utils.c Thu May 22 19:32:39 2008 +0200 @@ -10,7 +10,6 @@ #include <string.h> #include <stdlib.h> #include <audacious/plugin.h> -#include <audacious/util.h> const char *mp4AudioNames[]= {
--- a/src/adplug/adplug-xmms.cc Thu May 22 19:31:48 2008 +0200 +++ b/src/adplug/adplug-xmms.cc Thu May 22 19:32:39 2008 +0200 @@ -34,7 +34,6 @@ { #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> }
--- a/src/alac/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/alac/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -47,7 +47,6 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include "demux.h" #include "decomp.h"
--- a/src/alsa/Makefile Thu May 22 19:31:48 2008 +0200 +++ b/src/alsa/Makefile Thu May 22 19:32:39 2008 +0200 @@ -3,8 +3,7 @@ SRCS = alsa.c \ about.c \ audio.c \ - configure.c \ - init.c + configure.c include ../../buildsys.mk include ../../extra.mk
--- a/src/alsa/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/alsa/about.c Thu May 22 19:32:39 2008 +0200 @@ -17,7 +17,6 @@ */ #include "alsa.h" -#include <audacious/util.h> void alsa_about(void) {
--- a/src/alsa/alsa.c Thu May 22 19:31:48 2008 +0200 +++ b/src/alsa/alsa.c Thu May 22 19:32:39 2008 +0200 @@ -17,9 +17,64 @@ */ #include "alsa.h" +#include <glib.h> #include <stdlib.h> +#include <dlfcn.h> +#include <ctype.h> + +struct alsa_config alsa_cfg; + + +static void alsa_cleanup(void) +{ + if (alsa_cfg.pcm_device) { + free(alsa_cfg.pcm_device); + alsa_cfg.pcm_device = NULL; + } + + if (alsa_cfg.mixer_device) { + free(alsa_cfg.mixer_device); + alsa_cfg.mixer_device = NULL; + } +} + + +static void alsa_init(void) +{ + mcs_handle_t *cfgfile; -OutputPlugin alsa_op = + memset(&alsa_cfg, 0, sizeof (alsa_cfg)); + + alsa_cfg.buffer_time = 500; + alsa_cfg.period_time = 100; + alsa_cfg.debug = 0; + alsa_cfg.vol.left = 100; + alsa_cfg.vol.right = 100; + + cfgfile = aud_cfg_db_open(); + if (!aud_cfg_db_get_string(cfgfile, ALSA_CFGID, "pcm_device", + &alsa_cfg.pcm_device)) + alsa_cfg.pcm_device = g_strdup("default"); + g_message("device: %s", alsa_cfg.pcm_device); + if (!aud_cfg_db_get_string(cfgfile, ALSA_CFGID, "mixer_device", + &alsa_cfg.mixer_device)) + alsa_cfg.mixer_device = g_strdup("PCM"); + aud_cfg_db_get_int(cfgfile, ALSA_CFGID, "mixer_card", &alsa_cfg.mixer_card); + aud_cfg_db_get_int(cfgfile, ALSA_CFGID, "buffer_time", &alsa_cfg.buffer_time); + aud_cfg_db_get_int(cfgfile, ALSA_CFGID, "period_time", &alsa_cfg.period_time); + + aud_cfg_db_get_bool(cfgfile, ALSA_CFGID, "debug", &alsa_cfg.debug); + aud_cfg_db_close(cfgfile); + + if (dlopen("libasound.so.2", RTLD_NOW | RTLD_GLOBAL) == NULL) + { + g_message("Cannot load alsa library: %s", dlerror()); + /* FIXME, this plugin wont work... */ + } +} + + +static OutputPlugin alsa_op = { .description = "ALSA Output Plugin", .init = alsa_init, @@ -43,16 +98,3 @@ OutputPlugin *alsa_oplist[] = { &alsa_op, NULL }; DECLARE_PLUGIN(alsa, NULL, NULL, NULL, alsa_oplist, NULL, NULL, NULL, NULL) - -void alsa_cleanup(void) -{ - if (alsa_cfg.pcm_device) { - free(alsa_cfg.pcm_device); - alsa_cfg.pcm_device = NULL; - } - - if (alsa_cfg.mixer_device) { - free(alsa_cfg.mixer_device); - alsa_cfg.mixer_device = NULL; - } -}
--- a/src/alsa/alsa.h Thu May 22 19:31:48 2008 +0200 +++ b/src/alsa/alsa.h Thu May 22 19:32:39 2008 +0200 @@ -25,7 +25,6 @@ #include "config.h" -#include <audacious/util.h> #include <audacious/plugin.h> #include <audacious/i18n.h> @@ -36,11 +35,7 @@ #include <gtk/gtk.h> -#ifdef WORDS_BIGENDIAN -# define IS_BIG_ENDIAN TRUE -#else -# define IS_BIG_ENDIAN FALSE -#endif +#define ALSA_CFGID "ALSA" extern OutputPlugin op; @@ -60,8 +55,6 @@ extern struct alsa_config alsa_cfg; -void alsa_init(void); -void alsa_cleanup(void); void alsa_about(void); void alsa_configure(void); int alsa_get_mixer(snd_mixer_t **mixer, int card);
--- a/src/alsa/audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/alsa/audio.c Thu May 22 19:32:39 2008 +0200 @@ -68,8 +68,6 @@ static int prebuffer_size; GStaticMutex alsa_mutex = G_STATIC_MUTEX_INIT; -static guint mixer_timeout; - struct snd_format { unsigned int rate; unsigned int channels; @@ -463,20 +461,6 @@ return 0; } -static int alsa_mixer_timeout(void *data) -{ - if (mixer) - { - snd_mixer_close(mixer); - mixer = NULL; - pcm_element = NULL; - } - mixer_timeout = 0; - mixer_start = TRUE; - - return FALSE; -} - static void alsa_cleanup_mixer(void) { pcm_element = NULL; @@ -510,10 +494,6 @@ &lr); *l = ll; *r = lr; - - if (mixer_timeout) - gtk_timeout_remove(mixer_timeout); - mixer_timeout = gtk_timeout_add(5000, alsa_mixer_timeout, NULL); }
--- a/src/alsa/configure.c Thu May 22 19:31:48 2008 +0200 +++ b/src/alsa/configure.c Thu May 22 19:32:39 2008 +0200 @@ -48,13 +48,13 @@ { mcs_handle_t *cfgfile = aud_cfg_db_open(); - aud_cfg_db_set_int(cfgfile, "ALSA", "buffer_time", alsa_cfg.buffer_time); - aud_cfg_db_set_int(cfgfile, "ALSA", "period_time", alsa_cfg.period_time); - aud_cfg_db_set_string(cfgfile,"ALSA","pcm_device", alsa_cfg.pcm_device); - aud_cfg_db_set_int(cfgfile, "ALSA", "mixer_card", alsa_cfg.mixer_card); - aud_cfg_db_set_string(cfgfile,"ALSA","mixer_device", alsa_cfg.mixer_device); - aud_cfg_db_set_int(cfgfile, "ALSA", "volume_left", alsa_cfg.vol.left); - aud_cfg_db_set_int(cfgfile, "ALSA", "volume_right", alsa_cfg.vol.right); + aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "buffer_time", alsa_cfg.buffer_time); + aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "period_time", alsa_cfg.period_time); + aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"pcm_device", alsa_cfg.pcm_device); + aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "mixer_card", alsa_cfg.mixer_card); + aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"mixer_device", alsa_cfg.mixer_device); + aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_left", alsa_cfg.vol.left); + aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_right", alsa_cfg.vol.right); aud_cfg_db_close(cfgfile); }
--- a/src/alsa/init.c Thu May 22 19:31:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* XMMS - ALSA output plugin - * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org> - * Copyright (C) 2003-2005 Haavard Kvaalen - * - * 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 <glib.h> -#include "alsa.h" -#include <dlfcn.h> -#include <ctype.h> - -struct alsa_config alsa_cfg; - -void alsa_init(void) -{ - mcs_handle_t *cfgfile; - - memset(&alsa_cfg, 0, sizeof (alsa_cfg)); - alsa_cfg.buffer_time = 500; - alsa_cfg.period_time = 100; - alsa_cfg.debug = 0; - alsa_cfg.vol.left = 100; - alsa_cfg.vol.right = 100; - - cfgfile = aud_cfg_db_open(); - if (!aud_cfg_db_get_string(cfgfile, "ALSA", "pcm_device", - &alsa_cfg.pcm_device)) - alsa_cfg.pcm_device = g_strdup("default"); - g_message("device: %s", alsa_cfg.pcm_device); - if (!aud_cfg_db_get_string(cfgfile, "ALSA", "mixer_device", - &alsa_cfg.mixer_device)) - alsa_cfg.mixer_device = g_strdup("PCM"); - aud_cfg_db_get_int(cfgfile, "ALSA", "mixer_card", &alsa_cfg.mixer_card); - aud_cfg_db_get_int(cfgfile, "ALSA", "buffer_time", &alsa_cfg.buffer_time); - aud_cfg_db_get_int(cfgfile, "ALSA", "period_time", &alsa_cfg.period_time); - - aud_cfg_db_get_bool(cfgfile, "ALSA", "debug", &alsa_cfg.debug); - aud_cfg_db_close(cfgfile); - - if (dlopen("libasound.so.2", RTLD_NOW | RTLD_GLOBAL) == NULL) - { - g_message("Cannot load alsa library: %s", dlerror()); - /* FIXME, this plugin wont work... */ - } -}
--- a/src/amidi-plug/i_configure.c Thu May 22 19:31:48 2008 +0200 +++ b/src/amidi-plug/i_configure.c Thu May 22 19:32:39 2008 +0200 @@ -29,7 +29,6 @@ #include "i_configure-dummy.h" #include "i_utils.h" #include <audacious/auddrct.h> -#include <audacious/util.h> amidiplug_cfg_backend_t * amidiplug_cfg_backend;
--- a/src/aosd/aosd_trigger.c Thu May 22 19:31:48 2008 +0200 +++ b/src/aosd/aosd_trigger.c Thu May 22 19:32:39 2008 +0200 @@ -25,7 +25,6 @@ #include <glib.h> #include <audacious/i18n.h> #include <audacious/playlist.h> -#include <audacious/strings.h> #include <audacious/hook.h> #include <audacious/auddrct.h>
--- a/src/arts/arts.c Thu May 22 19:31:48 2008 +0200 +++ b/src/arts/arts.c Thu May 22 19:32:39 2008 +0200 @@ -10,7 +10,6 @@ */ #include "arts.h" -#include <audacious/util.h> static void about(void) {
--- a/src/audiocompress/audacious-glue.c Thu May 22 19:31:48 2008 +0200 +++ b/src/audiocompress/audacious-glue.c Thu May 22 19:32:39 2008 +0200 @@ -10,7 +10,6 @@ #include <gtk/gtk.h> #include <audacious/i18n.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include "audiocompress_config.h" #include "compress.h" @@ -37,6 +36,7 @@ static void myPrefs(void); static int myModify(gpointer * data, gint length, AFormat fmt, gint srate, gint nch); +static void myQueryFormat(AFormat * fmt, gint * rate, gint * nch); static int inited = 0; @@ -48,6 +48,7 @@ .about = myAbout, .configure = myPrefs, .mod_samples = myModify, + .query_format = myQueryFormat, }; EffectPlugin *audiocompress_eplist[] = { &xmms_plugin, NULL }; @@ -76,6 +77,14 @@ inited = 0; } +void myQueryFormat(AFormat * fmt, gint * rate, gint * nch) +{ + if ((*fmt != FMT_S16_NE) || + (*fmt != FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) || + (*fmt != FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN)) + *fmt = FMT_S16_NE; +} + int myModify(gpointer * data, gint length, AFormat fmt, gint srate, gint nch) { if (fmt == FMT_S16_NE ||
--- a/src/blur_scope/blur_scope.c Thu May 22 19:31:48 2008 +0200 +++ b/src/blur_scope/blur_scope.c Thu May 22 19:32:39 2008 +0200 @@ -26,7 +26,6 @@ #include <gtk/gtk.h> #include <string.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include "blur_scope.h" #include "bscope_logo.xpm"
--- a/src/cdaudio-ng/cdaudio-ng.c Thu May 22 19:31:48 2008 +0200 +++ b/src/cdaudio-ng/cdaudio-ng.c Thu May 22 19:32:39 2008 +0200 @@ -49,7 +49,6 @@ #include <audacious/i18n.h> #include <audacious/output.h> #include <audacious/ui_plugin_menu.h> -#include <audacious/util.h> #include "cdaudio-ng.h" #include "configure.h"
--- a/src/cdaudio-ng/cdaudio-ng.h Thu May 22 19:31:48 2008 +0200 +++ b/src/cdaudio-ng/cdaudio-ng.h Thu May 22 19:32:39 2008 +0200 @@ -21,10 +21,10 @@ #define CDAUDIO_NG_H -#define DEF_STRING_LEN 256 -#define CDDA_DUMMYPATH "cdda://" -#define CDDA_DAE_FRAMES 8 -#define CDDA_DEFAULT_LIMIT_SPEED 1 +#define DEF_STRING_LEN 256 +#define CDDA_DUMMYPATH "cdda://" +#define CDDA_DAE_FRAMES 8 +#define CDDA_DEFAULT_LIMIT_SPEED 1 #define CDDA_DEFAULT_CDDB_SERVER "freedb.org" #define CDDA_DEFAULT_CDDB_PORT 8880 #define CDDA_DEFAULT_PROXY_PORT 8080 @@ -46,7 +46,7 @@ lsn_t endlsn; lsn_t currlsn; lsn_t seektime; /* in miliseconds */ - InputPlayback *pplayback; + InputPlayback *pplayback; GThread *thread; } dae_params_t;
--- a/src/console/Audacious_Driver.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/console/Audacious_Driver.cxx Thu May 22 19:32:39 2008 +0200 @@ -13,7 +13,6 @@ #include <gtk/gtk.h> extern "C" { #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/output.h> } #include <string.h>
--- a/src/crystalizer/crystalizer.c Thu May 22 19:31:48 2008 +0200 +++ b/src/crystalizer/crystalizer.c Thu May 22 19:32:39 2008 +0200 @@ -21,19 +21,20 @@ #include <gtk/gtk.h> #include <audacious/i18n.h> -#include <audacious/util.h> #include <audacious/plugin.h> static void init(void); static void configure(void); static int mod_samples(gpointer *d, gint length, AFormat afmt, gint srate, gint nch); +static void query_format(AFormat * fmt, gint * rate, gint * nch); EffectPlugin crystalizer_ep = { .description = "Crystalizer", /* Description */ .init = init, .configure = configure, - .mod_samples = mod_samples + .mod_samples = mod_samples, + .query_format = query_format }; static GtkWidget *conf_dialog = NULL; @@ -138,6 +139,14 @@ gtk_widget_show(conf_dialog); } +static void query_format(AFormat * fmt, gint * rate, gint * nch) +{ + if (!(*fmt == FMT_S16_NE || + (*fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) || + (*fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN))) + *fmt = FMT_S16_NE; +} + static int mod_samples(gpointer *d, gint length, AFormat afmt, gint srate, gint nch) { gint i;
--- a/src/cue/cuesheet.c Thu May 22 19:31:48 2008 +0200 +++ b/src/cue/cuesheet.c Thu May 22 19:32:39 2008 +0200 @@ -25,8 +25,6 @@ #include <ctype.h> #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> -#include <audacious/strings.h> #define MAX_CUE_LINE_LENGTH 1000 #define MAX_CUE_TRACKS 1000
--- a/src/demac/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/demac/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -45,7 +45,6 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include "ape.h" #include "apev2.h"
--- a/src/dockalbumart/dockalbumart.c Thu May 22 19:31:48 2008 +0200 +++ b/src/dockalbumart/dockalbumart.c Thu May 22 19:32:39 2008 +0200 @@ -28,7 +28,6 @@ #include <Carbon/Carbon.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include "audacious_player.xpm"
--- a/src/echo_plugin/echo.c Thu May 22 19:31:48 2008 +0200 +++ b/src/echo_plugin/echo.c Thu May 22 19:32:39 2008 +0200 @@ -11,6 +11,7 @@ static void init(void); static void cleanup(void); static int mod_samples(gpointer * d, gint length, AFormat afmt, gint srate, gint nch); +static void query_format(AFormat * fmt, gint * rate, gint * nch); #define MAX_SRATE 50000 #define MAX_CHANNELS 2 @@ -27,6 +28,7 @@ .about = echo_about, .configure = echo_configure, .mod_samples = mod_samples, + .query_format = query_format, }; static gint16 *buffer = NULL; @@ -59,6 +61,14 @@ buffer = NULL; } +static void query_format(AFormat * fmt, gint * rate, gint * nch) +{ + if (!(*fmt == FMT_S16_NE || + (*fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) || + (*fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN))) + *fmt = FMT_S16_NE; +} + static int mod_samples(gpointer * d, gint length, AFormat afmt, gint srate, gint nch) { gint i, in, out, buf, r_ofs, fb_div;
--- a/src/echo_plugin/gui.c Thu May 22 19:31:48 2008 +0200 +++ b/src/echo_plugin/gui.c Thu May 22 19:32:39 2008 +0200 @@ -3,7 +3,6 @@ #include <gtk/gtk.h> #include <audacious/plugin.h> #include <audacious/i18n.h> -#include <audacious/util.h> #include "echo.h" static const char *echo_about_text =
--- a/src/esd/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/esd/about.c Thu May 22 19:32:39 2008 +0200 @@ -20,7 +20,6 @@ #include <audacious/i18n.h> #include <gtk/gtk.h> -#include <audacious/util.h> void
--- a/src/esd/audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/esd/audio.c Thu May 22 19:32:39 2008 +0200 @@ -25,7 +25,6 @@ #include <esd.h> #include <unistd.h> -#include <audacious/util.h> #include "esdout.h"
--- a/src/esd/mixer.c Thu May 22 19:31:48 2008 +0200 +++ b/src/esd/mixer.c Thu May 22 19:32:39 2008 +0200 @@ -24,7 +24,6 @@ #include <string.h> #include <esd.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h>
--- a/src/evdev-plug/ed_internals.c Thu May 22 19:31:48 2008 +0200 +++ b/src/evdev-plug/ed_internals.c Thu May 22 19:32:39 2008 +0200 @@ -24,7 +24,6 @@ #include "ed_bindings_store.h" #include "ed_common.h" -#include <audacious/util.h> #include <stdint.h> #include <stdio.h> #include <linux/input.h> @@ -36,7 +35,7 @@ #include <regex.h> /* for variadic */ #include <stdarg.h> - +#include <audacious/plugin.h> #include <audacious/i18n.h> #include <glib.h> #include <glib/gstdio.h>
--- a/src/filewriter/filewriter.h Thu May 22 19:31:48 2008 +0200 +++ b/src/filewriter/filewriter.h Thu May 22 19:32:39 2008 +0200 @@ -31,7 +31,6 @@ #include <audacious/plugin.h> #include <audacious/i18n.h> -#include <audacious/util.h> struct format_info { AFormat format;
--- a/src/flacng/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/flacng/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -19,7 +19,6 @@ /* #define FLACNG_DEBUG */ #include "flacng.h" -#include <audacious/util.h> #include <audacious/output.h> #include <audacious/i18n.h> #include "tools.h"
--- a/src/gnomeshortcuts/gnomeshortcuts.c Thu May 22 19:31:48 2008 +0200 +++ b/src/gnomeshortcuts/gnomeshortcuts.c Thu May 22 19:32:39 2008 +0200 @@ -32,7 +32,6 @@ #include <audacious/auddrct.h> #include <audacious/i18n.h> -#include <audacious/util.h> static void init (void);
--- a/src/hotkey/gui.c Thu May 22 19:31:48 2008 +0200 +++ b/src/hotkey/gui.c Thu May 22 19:32:39 2008 +0200 @@ -39,8 +39,8 @@ #include <gdk/gdkx.h> #include <gdk/gdkkeysyms.h> +#include <audacious/plugin.h> #include <audacious/i18n.h> -#include <audacious/util.h> #include "plugin.h" #include "gui.h" @@ -621,7 +621,7 @@ HotkeyConfiguration * old; old = hotkey; hotkey = hotkey->next; - free(old); + g_free(old); } plugin_cfg->first.next = NULL; plugin_cfg->first.key = 0; @@ -633,8 +633,7 @@ { if (controls->hotkey.key) { if (hotkey->key) { - hotkey->next = (HotkeyConfiguration*) - malloc(sizeof (HotkeyConfiguration)); + hotkey->next = g_new(HotkeyConfiguration, 1); hotkey = hotkey->next; hotkey->next = NULL; }
--- a/src/jack/jack.c Thu May 22 19:31:48 2008 +0200 +++ b/src/jack/jack.c Thu May 22 19:32:39 2008 +0200 @@ -7,7 +7,6 @@ */ #include <audacious/plugin.h> -#include <audacious/util.h> #include <dlfcn.h> #include <gtk/gtk.h> #include <audacious/i18n.h>
--- a/src/m3u/m3u.c Thu May 22 19:31:48 2008 +0200 +++ b/src/m3u/m3u.c Thu May 22 19:32:39 2008 +0200 @@ -34,8 +34,6 @@ #include <sys/errno.h> #include <audacious/plugin.h> -#include <audacious/util.h> -#include <audacious/strings.h> static void parse_extm3u_info(const gchar * info, gchar ** title, gint * length)
--- a/src/madplug/input.c Thu May 22 19:31:48 2008 +0200 +++ b/src/madplug/input.c Thu May 22 19:32:39 2008 +0200 @@ -55,7 +55,6 @@ #include <fcntl.h> #include <errno.h> -#include <audacious/util.h> #include "input.h" #include "replaygain.h"
--- a/src/madplug/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/madplug/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -28,7 +28,6 @@ #include <math.h> #include <gtk/gtk.h> -#include <audacious/util.h> #include <stdarg.h> #include <fcntl.h> #include <sys/stat.h>
--- a/src/madplug/plugin.h Thu May 22 19:31:48 2008 +0200 +++ b/src/madplug/plugin.h Thu May 22 19:32:39 2008 +0200 @@ -37,8 +37,6 @@ #include <string.h> #include <unistd.h> #include <audacious/plugin.h> -#include <audacious/util.h> -#include <audacious/strings.h> #include <audacious/i18n.h> #include <audacious/id3tag.h> #include <mad.h>
--- a/src/madplug/tuple.c Thu May 22 19:31:48 2008 +0200 +++ b/src/madplug/tuple.c Thu May 22 19:32:39 2008 +0200 @@ -31,7 +31,6 @@ #include <glib.h> #include <glib/gprintf.h> -#include <audacious/util.h> #include <audacious/plugin.h> #include <audacious/id3tag.h>
--- a/src/metronom/metronom.c Thu May 22 19:31:48 2008 +0200 +++ b/src/metronom/metronom.c Thu May 22 19:32:39 2008 +0200 @@ -20,7 +20,6 @@ #include "config.h" #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include <audacious/i18n.h> #include <glib.h> #include <string.h>
--- a/src/modplug/archive/arch_bz2.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/modplug/archive/arch_bz2.cxx Thu May 22 19:32:39 2008 +0200 @@ -40,7 +40,7 @@ return; } - if(fscanf(f, "%u", &mSize) != 1); // this is the size. + if(fscanf(f, "%u", &mSize) != 1) // this is the size. { mSize = 0; return;
--- a/src/modplug/gui/main.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/modplug/gui/main.cxx Thu May 22 19:32:39 2008 +0200 @@ -17,8 +17,6 @@ #include <gtk/gtk.h> #include <libintl.h> extern "C" { -#include <audacious/util.h> -#include <audacious/strings.h> } #include "interface.h"
--- a/src/modplug/modplugbmp.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/modplug/modplugbmp.cxx Thu May 22 19:32:39 2008 +0200 @@ -16,7 +16,6 @@ #include "archive/open.h" extern "C" { #include <audacious/output.h> -#include <audacious/strings.h> } static char* format_and_free_ti( Tuple* ti, int* length )
--- a/src/mtp_up/mtp.c Thu May 22 19:31:48 2008 +0200 +++ b/src/mtp_up/mtp.c Thu May 22 19:32:39 2008 +0200 @@ -26,7 +26,6 @@ #include <audacious/i18n.h> #include <gtk/gtk.h> -#include <audacious/util.h> #include "filetype.h" #define DEBUG 1
--- a/src/musepack/libmpc.h Thu May 22 19:31:48 2008 +0200 +++ b/src/musepack/libmpc.h Thu May 22 19:32:39 2008 +0200 @@ -8,7 +8,6 @@ { #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include <audacious/i18n.h> }
--- a/src/neon/neon.c Thu May 22 19:31:48 2008 +0200 +++ b/src/neon/neon.c Thu May 22 19:32:39 2008 +0200 @@ -862,7 +862,6 @@ */ VFSFile* neon_aud_vfs_fopen_impl(const gchar* path, const gchar* mode) { - VFSFile* file; struct neon_handle* handle;
--- a/src/null/null.c Thu May 22 19:31:48 2008 +0200 +++ b/src/null/null.c Thu May 22 19:32:39 2008 +0200 @@ -24,7 +24,6 @@ #include <gtk/gtk.h> #include <audacious/plugin.h> #include <audacious/i18n.h> -#include <audacious/util.h> static GTimer *timer; static gulong offset_time, written;
--- a/src/paranormal-ng/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/paranormal-ng/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -38,7 +38,6 @@ #include <gtk/gtk.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h>
--- a/src/paranormal/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/paranormal/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -38,7 +38,6 @@ #include <gtk/gtk.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <SDL.h> #include <SDL_thread.h>
--- a/src/pls/pls.c Thu May 22 19:31:48 2008 +0200 +++ b/src/pls/pls.c Thu May 22 19:32:39 2008 +0200 @@ -33,9 +33,7 @@ #include <sys/stat.h> #include <sys/errno.h> -#include <audacious/util.h> #include <audacious/plugin.h> -#include <audacious/strings.h> static void playlist_load_pls(const gchar * filename, gint pos)
--- a/src/projectm/main.c Thu May 22 19:31:48 2008 +0200 +++ b/src/projectm/main.c Thu May 22 19:32:39 2008 +0200 @@ -35,7 +35,6 @@ #include <string.h> #include <stdlib.h> #include <gtk/gtk.h> -#include <audacious/util.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #include <GL/gl.h>
--- a/src/pulse_audio/pulse_audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/pulse_audio/pulse_audio.c Thu May 22 19:32:39 2008 +0200 @@ -28,7 +28,6 @@ #include <gtk/gtk.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/i18n.h> #include <pulse/pulseaudio.h>
--- a/src/rootvis/rootvis.h Thu May 22 19:31:48 2008 +0200 +++ b/src/rootvis/rootvis.h Thu May 22 19:32:39 2008 +0200 @@ -4,7 +4,6 @@ #include <X11/Xatom.h> #include <X11/Xproto.h> #include <audacious/plugin.h> -#include <audacious/util.h> /* following values are used if there is no user configuration */
--- a/src/scrobbler/Makefile Thu May 22 19:31:48 2008 +0200 +++ b/src/scrobbler/Makefile Thu May 22 19:32:39 2008 +0200 @@ -3,7 +3,6 @@ SRCS = fmt.c \ configure.c \ gtkstuff.c \ - md5.c \ scrobbler.c \ gerpok.c \ plugin.c @@ -20,4 +19,4 @@ CFLAGS += ${PLUGIN_CFLAGS} CPPFLAGS += ${PLUGIN_CPPFLAGS} ${MOWGLI_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${BEEP_DEFINES} ${CURL_CFLAGS} -I../.. -LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${CURL_LIBS} ${MUSICBRAINZ_LIBS} ${MOWGLI_LIBS} +LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${CURL_LIBS} ${MUSICBRAINZ_LIBS} ${MOWGLI_LIBS} -laudutil
--- a/src/scrobbler/configure.c Thu May 22 19:31:48 2008 +0200 +++ b/src/scrobbler/configure.c Thu May 22 19:32:39 2008 +0200 @@ -1,9 +1,6 @@ #include "settings.h" -#include <config.h> - -#include <audacious/util.h> -#include <audacious/plugin.h> +#include "config.h" #include <sys/types.h> #include <sys/stat.h> @@ -11,9 +8,9 @@ #include <string.h> #include <stdio.h> -#include "md5.h" - #include <glib.h> +#include <audacious/plugin.h> +#include <audacious/audutil.h> #include <audacious/i18n.h> #include <gdk/gdkkeysyms.h> @@ -53,16 +50,16 @@ const char *ge_pwd = gtk_entry_get_text(GTK_ENTRY(ge_entry2)); if ((cfgfile = aud_cfg_db_open())) { - md5_state_t md5state; + aud_md5state_t md5state; unsigned char md5pword[16], ge_md5pword[16]; if (uid != NULL && uid[0] != '\0' && strlen(uid) && pwd != NULL && pwd[0] != '\0' && strlen(pwd)) { aud_cfg_db_set_string(cfgfile, "audioscrobbler", "username", (char *)uid); - md5_init(&md5state); - md5_append(&md5state, (unsigned const char *)pwd, strlen(pwd)); - md5_finish(&md5state, md5pword); + aud_md5_init(&md5state); + aud_md5_append(&md5state, (unsigned const char *)pwd, strlen(pwd)); + aud_md5_finish(&md5state, md5pword); aud_cfg_db_set_string(cfgfile, "audioscrobbler", "password", hexify((char*)md5pword, sizeof(md5pword))); } else if (!uid || uid[0] == '\0') { @@ -74,9 +71,9 @@ ge_pwd != NULL && ge_pwd[0] != '\0' && strlen(ge_pwd)) { aud_cfg_db_set_string(cfgfile, "audioscrobbler", "ge_username", (char *)ge_uid); - md5_init(&md5state); - md5_append(&md5state, (unsigned const char *)ge_pwd, strlen(ge_pwd)); - md5_finish(&md5state, ge_md5pword); + aud_md5_init(&md5state); + aud_md5_append(&md5state, (unsigned const char *)ge_pwd, strlen(ge_pwd)); + aud_md5_finish(&md5state, ge_md5pword); aud_cfg_db_set_string(cfgfile, "audioscrobbler", "ge_password", hexify((char*)ge_md5pword, sizeof(ge_md5pword))); } else if (!ge_uid || ge_uid[0] == '\0') {
--- a/src/scrobbler/gerpok.c Thu May 22 19:31:48 2008 +0200 +++ b/src/scrobbler/gerpok.c Thu May 22 19:32:39 2008 +0200 @@ -8,13 +8,11 @@ #include <curl/curl.h> #include <stdio.h> #include "fmt.h" -#include "md5.h" #include "scrobbler.h" #include "config.h" #include <glib.h> - #include <audacious/plugin.h> -#include <audacious/util.h> +#include <audacious/audutil.h> #define SCROBBLER_HS_URL "http://post.gerpok.com" #define SCROBBLER_CLI_ID "aud" @@ -446,17 +444,17 @@ } if (gerpok_sc_challenge_hash != NULL) { - md5_state_t md5state; + aud_md5state_t md5state; unsigned char md5pword[16]; - md5_init(&md5state); + aud_md5_init(&md5state); /*pdebug(fmt_vastr("Pass Hash: %s", gerpok_sc_password), DEBUG);*/ - md5_append(&md5state, (unsigned const char *)gerpok_sc_password, + aud_md5_append(&md5state, (unsigned const char *)gerpok_sc_password, strlen(gerpok_sc_password)); /*pdebug(fmt_vastr("Challenge Hash: %s", gerpok_sc_challenge_hash), DEBUG);*/ - md5_append(&md5state, (unsigned const char *)gerpok_sc_challenge_hash, + aud_md5_append(&md5state, (unsigned const char *)gerpok_sc_challenge_hash, strlen(gerpok_sc_challenge_hash)); - md5_finish(&md5state, md5pword); + aud_md5_finish(&md5state, md5pword); hexify((char*)md5pword, sizeof(md5pword)); /*pdebug(fmt_vastr("Response Hash: %s", gerpok_sc_response_hash), DEBUG);*/ }
--- a/src/scrobbler/gtkstuff.c Thu May 22 19:31:48 2008 +0200 +++ b/src/scrobbler/gtkstuff.c Thu May 22 19:32:39 2008 +0200 @@ -1,4 +1,3 @@ -#include <audacious/util.h> #include <glib.h> #include <audacious/i18n.h> @@ -8,7 +7,6 @@ #include <string.h> #include "settings.h" #include "config.h" -#include "md5.h" void about_show(void) {
--- a/src/scrobbler/md5.c Thu May 22 19:31:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.1 2003/08/24 01:20:37 audhov Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - <ghost@aladdin.com>. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include <string.h> - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include <stdio.h> in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include <string.h> - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -}
--- a/src/scrobbler/md5.h Thu May 22 19:31:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.1 2003/08/24 01:20:37 audhov Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - <ghost@aladdin.com>. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke <purschke@bnl.gov>. - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */
--- a/src/scrobbler/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/scrobbler/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -10,7 +10,6 @@ #include <audacious/plugin.h> #include <audacious/ui_preferences.h> #include <audacious/hook.h> -#include <audacious/strings.h> #include <unistd.h> #include <stdio.h>
--- a/src/scrobbler/scrobbler.c Thu May 22 19:31:48 2008 +0200 +++ b/src/scrobbler/scrobbler.c Thu May 22 19:32:39 2008 +0200 @@ -6,14 +6,13 @@ #include <curl/curl.h> #include <stdio.h> #include "fmt.h" -#include "md5.h" #include "scrobbler.h" #include "config.h" #include "settings.h" #include <glib.h> #include <audacious/plugin.h> -#include <audacious/util.h> +#include <audacious/audutil.h> #define SCROBBLER_HS_URL "http://post.audioscrobbler.com" #define SCROBBLER_CLI_ID "aud" @@ -441,12 +440,12 @@ static unsigned char *md5_string(char *pass, int len) { - md5_state_t md5state; + aud_md5state_t md5state; static unsigned char md5pword[16]; - md5_init(&md5state); - md5_append(&md5state, (unsigned const char *)pass, len); - md5_finish(&md5state, md5pword); + aud_md5_init(&md5state); + aud_md5_append(&md5state, (unsigned const char *)pass, len); + aud_md5_finish(&md5state, md5pword); return md5pword; } @@ -518,17 +517,17 @@ } if (sc_challenge_hash != NULL) { - md5_state_t md5state; + aud_md5state_t md5state; unsigned char md5pword[16]; - md5_init(&md5state); + aud_md5_init(&md5state); /*pdebug(fmt_vastr("Pass Hash: %s", sc_password), DEBUG);*/ - md5_append(&md5state, (unsigned const char *)sc_password, + aud_md5_append(&md5state, (unsigned const char *)sc_password, strlen(sc_password)); /*pdebug(fmt_vastr("Challenge Hash: %s", sc_challenge_hash), DEBUG);*/ - md5_append(&md5state, (unsigned const char *)sc_challenge_hash, + aud_md5_append(&md5state, (unsigned const char *)sc_challenge_hash, strlen(sc_challenge_hash)); - md5_finish(&md5state, md5pword); + aud_md5_finish(&md5state, md5pword); hexify((char*)md5pword, sizeof(md5pword)); /*pdebug(fmt_vastr("Response Hash: %s", sc_response_hash), DEBUG);*/ }
--- a/src/sexypsf/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sexypsf/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -18,7 +18,6 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
--- a/src/shnplug/gtk.c Thu May 22 19:31:48 2008 +0200 +++ b/src/shnplug/gtk.c Thu May 22 19:32:39 2008 +0200 @@ -22,7 +22,6 @@ #include <stdlib.h> #include <glib.h> -#include <audacious/util.h> #include "shorten.h" #undef XMMS_SHN_LOAD_TEXTFILES
--- a/src/shnplug/seek.c Thu May 22 19:31:48 2008 +0200 +++ b/src/shnplug/seek.c Thu May 22 19:32:39 2008 +0200 @@ -22,7 +22,6 @@ #include <stdlib.h> #include <glib.h> -#include <audacious/util.h> #include "shorten.h" #ifdef HAVE_CONFIG_H
--- a/src/shnplug/shn.c Thu May 22 19:31:48 2008 +0200 +++ b/src/shnplug/shn.c Thu May 22 19:32:39 2008 +0200 @@ -24,7 +24,6 @@ #include <stdlib.h> #include <math.h> #include <glib.h> -#include <audacious/util.h> #include "shorten.h" #ifdef HAVE_CONFIG_H
--- a/src/sid/Makefile Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/Makefile Thu May 22 19:32:39 2008 +0200 @@ -4,7 +4,6 @@ xs_about.c \ xs_support.c \ xs_config.c \ - xs_md5.c \ xs_length.c \ xs_genui.c \ xs_glade.c \ @@ -26,4 +25,4 @@ CFLAGS += ${PLUGIN_CFLAGS} CXXFLAGS += ${PLUGIN_CFLAGS} CPPFLAGS += ${PLUGIN_CPPFLAGS} -D_REENTRANT -I../.. -DAUDACIOUS_PLUGIN ${MOWGLI_CFLAGS} ${SIDPLAY1_CFLAGS} ${SIDPLAY2_CFLAGS} ${BUILDERS_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} -LIBS += ${BUILDERS_LDFLAGS} ${SIDPLAY1_LIBS} ${SIDPLAY2_LIBS} ${BUILDERS_LIBS} ${GTK_LIBS} ${GLIB_LIBS} -lstdc++ +LIBS += ${BUILDERS_LDFLAGS} ${SIDPLAY1_LIBS} ${SIDPLAY2_LIBS} ${BUILDERS_LIBS} ${GTK_LIBS} ${GLIB_LIBS} -lstdc++ -laudutil
--- a/src/sid/xs_config.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_config.c Thu May 22 19:32:39 2008 +0200 @@ -24,32 +24,32 @@ #ifdef AUDACIOUS_PLUGIN #include <audacious/plugin.h> -#define XS_CONFIG_FILE mcs_handle_t -#define XS_CONFIG_OPEN aud_cfg_db_open -#define XS_CONFIG_FREE aud_cfg_db_close +#define XS_CONFIG_FILE ConfigDb +#define XS_CONFIG_OPEN aud_cfg_db_open +#define XS_CONFIG_FREE aud_cfg_db_close -#define XS_CFG_SET_STRING aud_cfg_db_set_string -#define XS_CFG_SET_FLOAT aud_cfg_db_set_float -#define XS_CFG_SET_INT aud_cfg_db_set_int -#define XS_CFG_SET_BOOL aud_cfg_db_set_bool -#define XS_CFG_GET_STRING aud_cfg_db_get_string -#define XS_CFG_GET_FLOAT aud_cfg_db_get_float -#define XS_CFG_GET_INT aud_cfg_db_get_int -#define XS_CFG_GET_BOOL aud_cfg_db_get_bool +#define XS_CFG_SET_STRING aud_cfg_db_set_string +#define XS_CFG_SET_FLOAT aud_cfg_db_set_float +#define XS_CFG_SET_INT aud_cfg_db_set_int +#define XS_CFG_SET_BOOL aud_cfg_db_set_bool +#define XS_CFG_GET_STRING aud_cfg_db_get_string +#define XS_CFG_GET_FLOAT aud_cfg_db_get_float +#define XS_CFG_GET_INT aud_cfg_db_get_int +#define XS_CFG_GET_BOOL aud_cfg_db_get_bool #else #include <xmms/configfile.h> -#define XS_CONFIG_FILE ConfigFile -#define XS_CONFIG_OPEN xmms_cfg_open_default_file -#define XS_CONFIG_FREE xmms_cfg_free +#define XS_CONFIG_FILE ConfigFile +#define XS_CONFIG_OPEN xmms_cfg_open_default_file +#define XS_CONFIG_FREE xmms_cfg_free -#define XS_CFG_SET_STRING xmms_cfg_write_string -#define XS_CFG_SET_FLOAT xmms_cfg_write_float -#define XS_CFG_SET_INT xmms_cfg_write_int -#define XS_CFG_SET_BOOL xmms_cfg_write_boolean -#define XS_CFG_GET_STRING xmms_cfg_read_string -#define XS_CFG_GET_FLOAT xmms_cfg_read_float -#define XS_CFG_GET_INT xmms_cfg_read_int -#define XS_CFG_GET_BOOL xmms_cfg_read_boolean +#define XS_CFG_SET_STRING xmms_cfg_write_string +#define XS_CFG_SET_FLOAT xmms_cfg_write_float +#define XS_CFG_SET_INT xmms_cfg_write_int +#define XS_CFG_SET_BOOL xmms_cfg_write_boolean +#define XS_CFG_GET_STRING xmms_cfg_read_string +#define XS_CFG_GET_FLOAT xmms_cfg_read_float +#define XS_CFG_GET_INT xmms_cfg_read_int +#define XS_CFG_GET_BOOL xmms_cfg_read_boolean #endif #include <stdio.h> #include <ctype.h> @@ -87,116 +87,116 @@ struct t_xs_cfg xs_cfg; static t_xs_cfg_item xs_cfgtable[] = { -{ CTYPE_INT, &xs_cfg.audioBitsPerSample, "audioBitsPerSample" }, -{ CTYPE_INT, &xs_cfg.audioChannels, "audioChannels" }, -{ CTYPE_INT, &xs_cfg.audioFrequency, "audioFrequency" }, +{ CTYPE_INT, &xs_cfg.audioBitsPerSample, "audioBitsPerSample" }, +{ CTYPE_INT, &xs_cfg.audioChannels, "audioChannels" }, +{ CTYPE_INT, &xs_cfg.audioFrequency, "audioFrequency" }, -{ CTYPE_BOOL, &xs_cfg.mos8580, "mos8580" }, -{ CTYPE_BOOL, &xs_cfg.forceModel, "forceModel" }, -{ CTYPE_BOOL, &xs_cfg.emulateFilters, "emulateFilters" }, -{ CTYPE_FLOAT, &xs_cfg.sid1FilterFs, "filterFs" }, -{ CTYPE_FLOAT, &xs_cfg.sid1FilterFm, "filterFm" }, -{ CTYPE_FLOAT, &xs_cfg.sid1FilterFt, "filterFt" }, -{ CTYPE_INT, &xs_cfg.memoryMode, "memoryMode" }, -{ CTYPE_INT, &xs_cfg.clockSpeed, "clockSpeed" }, -{ CTYPE_BOOL, &xs_cfg.forceSpeed, "forceSpeed" }, +{ CTYPE_BOOL, &xs_cfg.mos8580, "mos8580" }, +{ CTYPE_BOOL, &xs_cfg.forceModel, "forceModel" }, +{ CTYPE_BOOL, &xs_cfg.emulateFilters, "emulateFilters" }, +{ CTYPE_FLOAT, &xs_cfg.sid1FilterFs, "filterFs" }, +{ CTYPE_FLOAT, &xs_cfg.sid1FilterFm, "filterFm" }, +{ CTYPE_FLOAT, &xs_cfg.sid1FilterFt, "filterFt" }, +{ CTYPE_INT, &xs_cfg.memoryMode, "memoryMode" }, +{ CTYPE_INT, &xs_cfg.clockSpeed, "clockSpeed" }, +{ CTYPE_BOOL, &xs_cfg.forceSpeed, "forceSpeed" }, -{ CTYPE_INT, &xs_cfg.playerEngine, "playerEngine" }, +{ CTYPE_INT, &xs_cfg.playerEngine, "playerEngine" }, -{ CTYPE_INT, &xs_cfg.sid2Builder, "sid2Builder" }, -{ CTYPE_INT, &xs_cfg.sid2OptLevel, "sid2OptLevel" }, -{ CTYPE_INT, &xs_cfg.sid2NFilterPresets, "sid2NFilterPresets" }, +{ CTYPE_INT, &xs_cfg.sid2Builder, "sid2Builder" }, +{ CTYPE_INT, &xs_cfg.sid2OptLevel, "sid2OptLevel" }, +{ CTYPE_INT, &xs_cfg.sid2NFilterPresets, "sid2NFilterPresets" }, -{ CTYPE_BOOL, &xs_cfg.oversampleEnable, "oversampleEnable" }, -{ CTYPE_INT, &xs_cfg.oversampleFactor, "oversampleFactor" }, +{ CTYPE_BOOL, &xs_cfg.oversampleEnable, "oversampleEnable" }, +{ CTYPE_INT, &xs_cfg.oversampleFactor, "oversampleFactor" }, -{ CTYPE_BOOL, &xs_cfg.playMaxTimeEnable, "playMaxTimeEnable" }, -{ CTYPE_BOOL, &xs_cfg.playMaxTimeUnknown, "playMaxTimeUnknown" }, -{ CTYPE_INT, &xs_cfg.playMaxTime, "playMaxTime" }, -{ CTYPE_BOOL, &xs_cfg.playMinTimeEnable, "playMinTimeEnable" }, -{ CTYPE_INT, &xs_cfg.playMinTime, "playMinTime" }, -{ CTYPE_BOOL, &xs_cfg.songlenDBEnable, "songlenDBEnable" }, -{ CTYPE_STR, &xs_cfg.songlenDBPath, "songlenDBPath" }, +{ CTYPE_BOOL, &xs_cfg.playMaxTimeEnable, "playMaxTimeEnable" }, +{ CTYPE_BOOL, &xs_cfg.playMaxTimeUnknown, "playMaxTimeUnknown" }, +{ CTYPE_INT, &xs_cfg.playMaxTime, "playMaxTime" }, +{ CTYPE_BOOL, &xs_cfg.playMinTimeEnable, "playMinTimeEnable" }, +{ CTYPE_INT, &xs_cfg.playMinTime, "playMinTime" }, +{ CTYPE_BOOL, &xs_cfg.songlenDBEnable, "songlenDBEnable" }, +{ CTYPE_STR, &xs_cfg.songlenDBPath, "songlenDBPath" }, -{ CTYPE_BOOL, &xs_cfg.stilDBEnable, "stilDBEnable" }, -{ CTYPE_STR, &xs_cfg.stilDBPath, "stilDBPath" }, -{ CTYPE_STR, &xs_cfg.hvscPath, "hvscPath" }, +{ CTYPE_BOOL, &xs_cfg.stilDBEnable, "stilDBEnable" }, +{ CTYPE_STR, &xs_cfg.stilDBPath, "stilDBPath" }, +{ CTYPE_STR, &xs_cfg.hvscPath, "hvscPath" }, #ifndef AUDACIOUS_PLUGIN -{ CTYPE_INT, &xs_cfg.subsongControl, "subsongControl" }, -{ CTYPE_BOOL, &xs_cfg.detectMagic, "detectMagic" }, +{ CTYPE_INT, &xs_cfg.subsongControl, "subsongControl" }, +{ CTYPE_BOOL, &xs_cfg.detectMagic, "detectMagic" }, #endif -{ CTYPE_BOOL, &xs_cfg.titleOverride, "titleOverride" }, -{ CTYPE_STR, &xs_cfg.titleFormat, "titleFormat" }, +{ CTYPE_BOOL, &xs_cfg.titleOverride, "titleOverride" }, +{ CTYPE_STR, &xs_cfg.titleFormat, "titleFormat" }, -{ CTYPE_BOOL, &xs_cfg.subAutoEnable, "subAutoEnable" }, -{ CTYPE_BOOL, &xs_cfg.subAutoMinOnly, "subAutoMinOnly" }, -{ CTYPE_INT, &xs_cfg.subAutoMinTime, "subAutoMinTime" }, +{ CTYPE_BOOL, &xs_cfg.subAutoEnable, "subAutoEnable" }, +{ CTYPE_BOOL, &xs_cfg.subAutoMinOnly, "subAutoMinOnly" }, +{ CTYPE_INT, &xs_cfg.subAutoMinTime, "subAutoMinTime" }, }; static const gint xs_cfgtable_max = (sizeof(xs_cfgtable) / sizeof(t_xs_cfg_item)); static t_xs_wid_item xs_widtable[] = { -{ WTYPE_BGROUP, CTYPE_INT, "cfg_res_16bit", &xs_cfg.audioBitsPerSample, XS_RES_16BIT }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_res_8bit", &xs_cfg.audioBitsPerSample, XS_RES_8BIT }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_chn_mono", &xs_cfg.audioChannels, XS_CHN_MONO }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_chn_stereo", &xs_cfg.audioChannels, XS_CHN_STEREO }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_chn_autopan", &xs_cfg.audioChannels, XS_CHN_AUTOPAN }, -{ WTYPE_COMBO, CTYPE_INT, "cfg_samplerate", &xs_cfg.audioFrequency, XS_AUDIO_FREQ }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_oversample", &xs_cfg.oversampleEnable, 0 }, -{ WTYPE_SPIN, CTYPE_INT, "cfg_oversample_factor",&xs_cfg.oversampleFactor, 0 }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_res_16bit", &xs_cfg.audioBitsPerSample, XS_RES_16BIT }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_res_8bit", &xs_cfg.audioBitsPerSample, XS_RES_8BIT }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_chn_mono", &xs_cfg.audioChannels, XS_CHN_MONO }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_chn_stereo", &xs_cfg.audioChannels, XS_CHN_STEREO }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_chn_autopan", &xs_cfg.audioChannels, XS_CHN_AUTOPAN }, +{ WTYPE_COMBO, CTYPE_INT, "cfg_samplerate", &xs_cfg.audioFrequency, XS_AUDIO_FREQ }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_oversample", &xs_cfg.oversampleEnable, 0 }, +{ WTYPE_SPIN, CTYPE_INT, "cfg_oversample_factor",&xs_cfg.oversampleFactor, 0 }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sidplay1", &xs_cfg.playerEngine, XS_ENG_SIDPLAY1 }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sidplay2", &xs_cfg.playerEngine, XS_ENG_SIDPLAY2 }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_real", &xs_cfg.memoryMode, XS_MPU_REAL }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_banksw", &xs_cfg.memoryMode, XS_MPU_BANK_SWITCHING }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_transrom", &xs_cfg.memoryMode, XS_MPU_TRANSPARENT_ROM }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_playsid", &xs_cfg.memoryMode, XS_MPU_PLAYSID_ENVIRONMENT }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sidplay1", &xs_cfg.playerEngine, XS_ENG_SIDPLAY1 }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sidplay2", &xs_cfg.playerEngine, XS_ENG_SIDPLAY2 }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_real", &xs_cfg.memoryMode, XS_MPU_REAL }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_banksw", &xs_cfg.memoryMode, XS_MPU_BANK_SWITCHING }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_transrom", &xs_cfg.memoryMode, XS_MPU_TRANSPARENT_ROM }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_mem_playsid", &xs_cfg.memoryMode, XS_MPU_PLAYSID_ENVIRONMENT }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_mos8580", &xs_cfg.mos8580, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_sid_force", &xs_cfg.forceModel, 0 }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_clock_ntsc", &xs_cfg.clockSpeed, XS_CLOCK_NTSC }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_clock_pal", &xs_cfg.clockSpeed, XS_CLOCK_PAL }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_clock_force", &xs_cfg.forceSpeed, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_sp2_opt", &xs_cfg.sid2OptLevel, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_mos8580", &xs_cfg.mos8580, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_sid_force", &xs_cfg.forceModel, 0 }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_clock_ntsc", &xs_cfg.clockSpeed, XS_CLOCK_NTSC }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_clock_pal", &xs_cfg.clockSpeed, XS_CLOCK_PAL }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_clock_force", &xs_cfg.forceSpeed, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_sp2_opt", &xs_cfg.sid2OptLevel, 0 }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sp2_resid", &xs_cfg.sid2Builder, XS_BLD_RESID }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sp2_hardsid", &xs_cfg.sid2Builder, XS_BLD_HARDSID }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sp2_resid", &xs_cfg.sid2Builder, XS_BLD_RESID }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_emu_sp2_hardsid", &xs_cfg.sid2Builder, XS_BLD_HARDSID }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_filters", &xs_cfg.emulateFilters, 0 }, -{ WTYPE_SCALE, CTYPE_FLOAT, "cfg_sp1_filter_fs", &xs_cfg.sid1FilterFs, 0 }, -{ WTYPE_SCALE, CTYPE_FLOAT, "cfg_sp1_filter_fm", &xs_cfg.sid1FilterFm, 0 }, -{ WTYPE_SCALE, CTYPE_FLOAT, "cfg_sp1_filter_ft", &xs_cfg.sid1FilterFt, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_emu_filters", &xs_cfg.emulateFilters, 0 }, +{ WTYPE_SCALE, CTYPE_FLOAT, "cfg_sp1_filter_fs", &xs_cfg.sid1FilterFs, 0 }, +{ WTYPE_SCALE, CTYPE_FLOAT, "cfg_sp1_filter_fm", &xs_cfg.sid1FilterFm, 0 }, +{ WTYPE_SCALE, CTYPE_FLOAT, "cfg_sp1_filter_ft", &xs_cfg.sid1FilterFt, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_maxtime_enable", &xs_cfg.playMaxTimeEnable, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_maxtime_unknown", &xs_cfg.playMaxTimeUnknown, 0 }, -{ WTYPE_SPIN, CTYPE_INT, "cfg_maxtime", &xs_cfg.playMaxTime, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_mintime_enable", &xs_cfg.playMinTimeEnable, 0 }, -{ WTYPE_SPIN, CTYPE_INT, "cfg_mintime", &xs_cfg.playMinTime, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_sld_enable", &xs_cfg.songlenDBEnable, 0 }, -{ WTYPE_TEXT, CTYPE_STR, "cfg_sld_dbpath", &xs_cfg.songlenDBPath, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_maxtime_enable", &xs_cfg.playMaxTimeEnable, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_maxtime_unknown", &xs_cfg.playMaxTimeUnknown, 0 }, +{ WTYPE_SPIN, CTYPE_INT, "cfg_maxtime", &xs_cfg.playMaxTime, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_mintime_enable", &xs_cfg.playMinTimeEnable, 0 }, +{ WTYPE_SPIN, CTYPE_INT, "cfg_mintime", &xs_cfg.playMinTime, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_sld_enable", &xs_cfg.songlenDBEnable, 0 }, +{ WTYPE_TEXT, CTYPE_STR, "cfg_sld_dbpath", &xs_cfg.songlenDBPath, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_stil_enable", &xs_cfg.stilDBEnable, 0 }, -{ WTYPE_TEXT, CTYPE_STR, "cfg_stil_dbpath", &xs_cfg.stilDBPath, 0 }, -{ WTYPE_TEXT, CTYPE_STR, "cfg_hvsc_path", &xs_cfg.hvscPath, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_stil_enable", &xs_cfg.stilDBEnable, 0 }, +{ WTYPE_TEXT, CTYPE_STR, "cfg_stil_dbpath", &xs_cfg.stilDBPath, 0 }, +{ WTYPE_TEXT, CTYPE_STR, "cfg_hvsc_path", &xs_cfg.hvscPath, 0 }, #ifndef AUDACIOUS_PLUGIN -{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_none", &xs_cfg.subsongControl, XS_SSC_NONE }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_seek", &xs_cfg.subsongControl, XS_SSC_SEEK }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_popup", &xs_cfg.subsongControl, XS_SSC_POPUP }, -{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_patch", &xs_cfg.subsongControl, XS_SSC_PATCH }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_none", &xs_cfg.subsongControl, XS_SSC_NONE }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_seek", &xs_cfg.subsongControl, XS_SSC_SEEK }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_popup", &xs_cfg.subsongControl, XS_SSC_POPUP }, +{ WTYPE_BGROUP, CTYPE_INT, "cfg_subctrl_patch", &xs_cfg.subsongControl, XS_SSC_PATCH }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_detectmagic", &xs_cfg.detectMagic, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_detectmagic", &xs_cfg.detectMagic, 0 }, #endif -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_ftitle_override", &xs_cfg.titleOverride, 0 }, -{ WTYPE_TEXT, CTYPE_STR, "cfg_ftitle_format", &xs_cfg.titleFormat, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_ftitle_override", &xs_cfg.titleOverride, 0 }, +{ WTYPE_TEXT, CTYPE_STR, "cfg_ftitle_format", &xs_cfg.titleFormat, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_subauto_enable", &xs_cfg.subAutoEnable, 0 }, -{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_subauto_min_only", &xs_cfg.subAutoMinOnly, 0 }, -{ WTYPE_SPIN, CTYPE_INT, "cfg_subauto_mintime", &xs_cfg.subAutoMinTime, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_subauto_enable", &xs_cfg.subAutoEnable, 0 }, +{ WTYPE_BUTTON, CTYPE_BOOL, "cfg_subauto_min_only", &xs_cfg.subAutoMinOnly, 0 }, +{ WTYPE_SPIN, CTYPE_INT, "cfg_subauto_mintime", &xs_cfg.subAutoMinTime, 0 }, }; static const gint xs_widtable_max = (sizeof(xs_widtable) / sizeof(t_xs_wid_item));
--- a/src/sid/xs_config.h Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_config.h Thu May 22 19:32:39 2008 +0200 @@ -81,54 +81,54 @@ gint audioFrequency; gboolean oversampleEnable; - gint oversampleFactor; /* Factor of oversampling */ + gint oversampleFactor; /* Factor of oversampling */ /* Emulation settings */ - gboolean mos8580; /* TRUE = 8580, FALSE = 6581 */ + gboolean mos8580; /* TRUE = 8580, FALSE = 6581 */ gboolean forceModel; - gint memoryMode; /* See XS_MPU-constants */ - gint clockSpeed; /* PAL (50Hz) or NTSC (60Hz) */ - gboolean forceSpeed; /* TRUE = force to given clockspeed */ + gint memoryMode; /* See XS_MPU-constants */ + gint clockSpeed; /* PAL (50Hz) or NTSC (60Hz) */ + gboolean forceSpeed; /* TRUE = force to given clockspeed */ - gint playerEngine; /* Selected player engine */ + gint playerEngine; /* Selected player engine */ gboolean emulateFilters; - gfloat sid1FilterFs; - gfloat sid1FilterFm; - gfloat sid1FilterFt; + gfloat sid1FilterFs; + gfloat sid1FilterFm; + gfloat sid1FilterFt; - gint sid2OptLevel; /* SIDPlay2 emulation optimization */ + gint sid2OptLevel; /* SIDPlay2 emulation optimization */ gint sid2Builder; /* SIDPlay2 "builder" aka SID-emu */ - t_xs_sid2_filter sid2Filter; /* Current SIDPlay2 filter */ + t_xs_sid2_filter sid2Filter; /* Current SIDPlay2 filter */ t_xs_sid2_filter **sid2FilterPresets; gint sid2NFilterPresets; /* Playing settings */ gboolean playMaxTimeEnable, - playMaxTimeUnknown; /* Use max-time only when song-length is unknown */ + playMaxTimeUnknown; /* Use max-time only when song-length is unknown */ gint playMaxTime; /* MAX playtime in seconds */ gboolean playMinTimeEnable; gint playMinTime; /* MIN playtime in seconds */ gboolean songlenDBEnable; - gchar *songlenDBPath; /* Path to Songlengths.txt */ + gchar *songlenDBPath; /* Path to Songlengths.txt */ /* Miscellaneous settings */ gboolean stilDBEnable; - gchar *stilDBPath; /* Path to STIL.txt */ - gchar *hvscPath; /* Path-prefix for HVSC */ + gchar *stilDBPath; /* Path to STIL.txt */ + gchar *hvscPath; /* Path-prefix for HVSC */ gint subsongControl; gboolean detectMagic; - gboolean titleOverride; /* TRUE if XMMS titles are overriden */ - gchar *titleFormat; + gboolean titleOverride; /* TRUE if XMMS titles are overriden */ + gchar *titleFormat; gboolean subAutoEnable, - subAutoMinOnly; + subAutoMinOnly; gint subAutoMinTime; } xs_cfg; @@ -155,16 +155,16 @@ typedef struct { - gint itemType; /* Type of item (CTYPE_*) */ - void *itemData; /* Pointer to variable */ - gchar *itemName; /* Name of configuration item */ + gint itemType; /* Type of item (CTYPE_*) */ + void *itemData; /* Pointer to variable */ + gchar *itemName; /* Name of configuration item */ } t_xs_cfg_item; typedef struct { gint widType; gint itemType; - gchar *widName; + gchar *widName; void *itemData; gint itemSet; } t_xs_wid_item;
--- a/src/sid/xs_length.h Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_length.h Thu May 22 19:32:39 2008 +0200 @@ -2,7 +2,18 @@ #define XS_LENGTH_H #include "xmms-sid.h" +#ifdef AUDACIOUS_PLUGIN +#include <audacious/audutil.h> +#define XS_MD5HASH_LENGTH AUD_MD5HASH_LENGTH +#define XS_MD5HASH_LENGTH_CH AUD_MD5HASH_LENGTH_CH +#define xs_md5hash_t aud_md5hash_t +#define xs_md5state_t aud_md5state_t +#define xs_md5_init aud_md5_init +#define xs_md5_append aud_md5_append +#define xs_md5_finish aud_md5_finish +#else #include "xs_md5.h" +#endif #ifdef __cplusplus extern "C" { @@ -12,25 +23,25 @@ */ typedef struct _sldb_node_t { xs_md5hash_t md5Hash; /* 128-bit MD5 hash-digest */ - gint nlengths; /* Number of lengths */ - gint *lengths; /* Lengths in seconds */ + gint nlengths; /* Number of lengths */ + gint *lengths; /* Lengths in seconds */ struct _sldb_node_t *prev, *next; } sldb_node_t; typedef struct { - sldb_node_t *nodes, - **pindex; - size_t n; + sldb_node_t *nodes, + **pindex; + size_t n; } xs_sldb_t; /* Functions */ -gint xs_sldb_read(xs_sldb_t *, const gchar *); -gint xs_sldb_index(xs_sldb_t *); -void xs_sldb_free(xs_sldb_t *); -sldb_node_t * xs_sldb_get(xs_sldb_t *, const gchar *); +gint xs_sldb_read(xs_sldb_t *, const gchar *); +gint xs_sldb_index(xs_sldb_t *); +void xs_sldb_free(xs_sldb_t *); +sldb_node_t * xs_sldb_get(xs_sldb_t *, const gchar *); #ifdef __cplusplus }
--- a/src/sid/xs_md5.c Thu May 22 19:31:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,230 +0,0 @@ -/* - * MD5 implementation, modified for XMMS-SID from - * Colin Plumb's implementation by Matti 'ccr' Hämäläinen. - * - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - */ -#include "xs_support.h" -#include "xs_md5.h" -#include <glib.h> - - -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define xs_md5_bytereverse(buf, len) /* Nothing */ -#else -#if G_BYTE_ORDER == G_BIG_ENDIAN -static void xs_md5_bytereverse(guint8 *buf, guint l) -{ - guint32 t; - do { - t = (guint32) ((guint) buf[3] << 8 | buf[2]) << 16 | ((guint) buf[1] << 8 | buf[0]); - *(guint32 *) buf = t; - buf += sizeof(guint32); - } while (--l); -} -#else -#error Unsupported endianess! -#endif -#endif - - -/* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void xs_md5_init(xs_md5state_t *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - - -/* The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. xs_md5_update blocks - * the data and converts bytes into longwords for this routine. - */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -static void xs_md5_transform(guint32 buf[4], guint32 const in[16]) -{ - register guint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - - -/* Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void xs_md5_append(xs_md5state_t *ctx, const guint8 *buf, guint len) -{ - guint32 t; - - /* Update bitcount */ - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((guint32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - if (t) { - guint8 *p = (guint8 *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - xs_md5_bytereverse(ctx->in, 16); - xs_md5_transform(ctx->buf, (guint32 *) ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - while (len >= 64) { - memcpy(ctx->in, buf, 64); - xs_md5_bytereverse(ctx->in, 16); - xs_md5_transform(ctx->buf, (guint32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); -} - -/* Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void xs_md5_finish(xs_md5state_t *ctx, xs_md5hash_t digest) -{ - guint count; - guint8 *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - xs_md5_bytereverse(ctx->in, 16); - xs_md5_transform(ctx->buf, (guint32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - xs_md5_bytereverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((guint32 *) ctx->in)[14] = ctx->bits[0]; - ((guint32 *) ctx->in)[15] = ctx->bits[1]; - - xs_md5_transform(ctx->buf, (guint32 *) ctx->in); - xs_md5_bytereverse((guint8 *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -}
--- a/src/sid/xs_md5.h Thu May 22 19:31:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -#ifndef XS_MD5_H -#define XS_MD5_H - -#include <glib.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* Typedefs - */ -typedef struct md5_state_s { - guint32 bits[2]; /* message length in bits, lsw first */ - guint32 buf[4]; /* digest buffer */ - guint8 in[64]; /* accumulate block */ -} xs_md5state_t; - -#define XS_MD5HASH_LENGTH (16) -#define XS_MD5HASH_LENGTH_CH (XS_MD5HASH_LENGTH * 2) - -typedef guint8 xs_md5hash_t[XS_MD5HASH_LENGTH]; - - -/* Functions - */ -void xs_md5_init(xs_md5state_t *ctx); -void xs_md5_append(xs_md5state_t *ctx, const guint8 *buf, guint len); -void xs_md5_finish(xs_md5state_t *ctx, xs_md5hash_t digest); - - -#ifdef __cplusplus -} -#endif -#endif /* XS_MD5_H */
--- a/src/sid/xs_player.h Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_player.h Thu May 22 19:32:39 2008 +0200 @@ -16,7 +16,7 @@ gboolean (*plrInit)(struct xs_status_t *); void (*plrClose)(struct xs_status_t *); gboolean (*plrInitSong)(struct xs_status_t *); - guint (*plrFillBuffer)(struct xs_status_t *, gchar *, guint); + guint (*plrFillBuffer)(struct xs_status_t *, gchar *, guint); gboolean (*plrLoadSID)(struct xs_status_t *, gchar *); void (*plrDeleteSID)(struct xs_status_t *); xs_tuneinfo_t* (*plrGetSIDInfo)(const gchar *); @@ -26,22 +26,24 @@ typedef struct xs_status_t { - gint audioFrequency, /* Audio settings */ - audioChannels, - audioBitsPerSample, - oversampleFactor; /* Factor of oversampling */ - AFormat audioFormat; - gboolean oversampleEnable; /* TRUE after sidEngine initialization, - if xs_cfg.oversampleEnable == TRUE and - emulation backend supports oversampling. - */ - void *sidEngine; /* SID-emulation internal engine data */ - xs_player_t *sidPlayer; /* Selected player engine */ - gboolean isError, isPlaying, isInitialized; - gint currSong, /* Current sub-tune */ - lastTime; + gint audioFrequency, /* Audio settings */ + audioChannels, + audioBitsPerSample, + oversampleFactor; /* Factor of oversampling */ + AFormat audioFormat; + gboolean oversampleEnable; /* TRUE after sidEngine initialization, + if xs_cfg.oversampleEnable == TRUE and + emulation backend supports oversampling. + */ + void *sidEngine; /* SID-emulation internal engine data */ + xs_player_t *sidPlayer; /* Selected player engine */ + gboolean isError, + isPlaying, + isInitialized; + gint currSong, /* Current sub-tune */ + lastTime; - xs_tuneinfo_t *tuneInfo; + xs_tuneinfo_t *tuneInfo; } xs_status_t;
--- a/src/sid/xs_sidplay1.cc Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_sidplay1.cc Thu May 22 19:32:39 2008 +0200 @@ -52,11 +52,11 @@ /* Return song information */ -#define TFUNCTION xs_sidplay1_getinfo -#define TFUNCTION2 xs_sidplay1_updateinfo -#define TTUNEINFO sidTuneInfo -#define TTUNE sidTune -#define TENGINE xs_sidplay1_t +#define TFUNCTION xs_sidplay1_getinfo +#define TFUNCTION2 xs_sidplay1_updateinfo +#define TTUNEINFO sidTuneInfo +#define TTUNE sidTune +#define TENGINE xs_sidplay1_t #include "xs_sidplay.h"
--- a/src/sid/xs_sidplay2.cc Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_sidplay2.cc Thu May 22 19:32:39 2008 +0200 @@ -30,22 +30,50 @@ #include <sidplay/sidplay2.h> -#ifdef HAVE_RESID_BUILDER -#include <sidplay/builders/resid.h> -#endif -#ifdef HAVE_HARDSID_BUILDER -#include <sidplay/builders/hardsid.h> +#ifdef HAVE_SIDPLAY2_COMI +# include <sidplay/sidlazyiptr.h> #endif -typedef struct { +class xs_sidplay2_t { +public: +#ifdef HAVE_SIDPLAY2_COMI + SidIPtr<ISidplay2> currEng; + SidLazyIPtr<ISidUnknown> currBuilder; +#else sidplay2 *currEng; sidbuilder *currBuilder; +#endif sid2_config_t currConfig; SidTune *currTune; guint8 *buf; size_t bufSize; -} xs_sidplay2_t; + + xs_sidplay2_t(void); + virtual ~xs_sidplay2_t(void) { ; } +}; + + +#ifdef HAVE_RESID_BUILDER +# include <sidplay/builders/resid.h> +#endif +#ifdef HAVE_HARDSID_BUILDER +# include <sidplay/builders/hardsid.h> +#endif + + +xs_sidplay2_t::xs_sidplay2_t(void) +#ifdef HAVE_SIDPLAY2_COMI +:currEng(sidplay2::create()) +#else +:currEng(NULL) +#endif +{ + buf = NULL; + bufSize = 0; + currTune = NULL; + currBuilder = NULL; +} /* We need to 'export' all this pseudo-C++ crap */ @@ -54,11 +82,11 @@ /* Return song information */ -#define TFUNCTION xs_sidplay2_getinfo -#define TFUNCTION2 xs_sidplay2_updateinfo -#define TTUNEINFO SidTuneInfo -#define TTUNE SidTune -#define TENGINE xs_sidplay2_t +#define TFUNCTION xs_sidplay2_getinfo +#define TFUNCTION2 xs_sidplay2_updateinfo +#define TTUNEINFO SidTuneInfo +#define TTUNE SidTune +#define TENGINE xs_sidplay2_t #include "xs_sidplay.h" @@ -91,12 +119,14 @@ assert(myStatus); /* Allocate internal structures */ - myEngine = (xs_sidplay2_t *) g_malloc0(sizeof(xs_sidplay2_t)); + myEngine = new xs_sidplay2_t(); myStatus->sidEngine = myEngine; if (!myEngine) return FALSE; /* Initialize the engine */ +#ifndef HAVE_SIDPLAY2_COMI myEngine->currEng = new sidplay2; +#endif if (!myEngine->currEng) { xs_error("[SIDPlay2] Could not initialize emulation engine.\n"); return FALSE; @@ -228,9 +258,16 @@ XSDEBUG("init builder #%i, maxsids=%i\n", xs_cfg.sid2Builder, (myEngine->currEng->info()).maxsids); #ifdef HAVE_RESID_BUILDER if (xs_cfg.sid2Builder == XS_BLD_RESID) { +#ifdef HAVE_SIDPLAY2_COMI + myEngine->currBuilder = ReSIDBuilderCreate(""); + SidLazyIPtr<IReSIDBuilder> rs(myEngine->currBuilder); + if (rs) { + myEngine->currConfig.sidEmulation = rs->iaggregate(); +#else ReSIDBuilder *rs = new ReSIDBuilder("ReSID builder"); myEngine->currBuilder = (sidbuilder *) rs; if (rs) { +#endif /* Builder object created, initialize it */ rs->create((myEngine->currEng->info()).maxsids); if (!*rs) { @@ -266,9 +303,16 @@ #endif #ifdef HAVE_HARDSID_BUILDER if (xs_cfg.sid2Builder == XS_BLD_HARDSID) { +#ifdef HAVE_SIDPLAY2_COMI + myEngine->currBuilder = HardSIDBuilderCreate(""); + SidLazyIPtr<IHardSIDBuilder> hs(myEngine->currBuilder); + if (hs) { + myEngine->currConfig.sidEmulation = hs->iaggregate(); +#else HardSIDBuilder *hs = new HardSIDBuilder("HardSID builder"); myEngine->currBuilder = (sidbuilder *) hs; if (hs) { +#endif /* Builder object created, initialize it */ hs->create((myEngine->currEng->info()).maxsids); if (!*hs) { @@ -290,8 +334,10 @@ return FALSE; } +#ifndef HAVE_SIDPLAY2_COMI + myEngine->currConfig.sidEmulation = myEngine->currBuilder; XSDEBUG("%s\n", myEngine->currBuilder->credits()); - +#endif /* Clockspeed settings */ switch (xs_cfg.clockSpeed) { @@ -311,7 +357,6 @@ /* Configure rest of the emulation */ - myEngine->currConfig.sidEmulation = myEngine->currBuilder; if (xs_cfg.forceSpeed) { myEngine->currConfig.clockForced = true; @@ -374,14 +419,18 @@ /* Free internals */ if (myEngine->currBuilder) { +#ifndef HAVE_SIDPLAY2_COMI delete myEngine->currBuilder; +#endif myEngine->currBuilder = NULL; } +#ifndef HAVE_SIDPLAY2_COMI if (myEngine->currEng) { delete myEngine->currEng; myEngine->currEng = NULL; } +#endif if (myEngine->currTune) { delete myEngine->currTune; @@ -390,7 +439,7 @@ xs_sidplay2_delete(myStatus); - g_free(myEngine); + delete myEngine; myStatus->sidEngine = NULL; }
--- a/src/sid/xs_slsup.h Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_slsup.h Thu May 22 19:32:39 2008 +0200 @@ -11,18 +11,18 @@ gint xs_stil_init(void); void xs_stil_close(void); -stil_node_t *xs_stil_get(gchar *filename); +stil_node_t *xs_stil_get(gchar *filename); gint xs_songlen_init(void); void xs_songlen_close(void); -sldb_node_t *xs_songlen_get(const gchar *); +sldb_node_t *xs_songlen_get(const gchar *); -xs_tuneinfo_t *xs_tuneinfo_new(const gchar * pcFilename, - gint nsubTunes, gint startTune, const gchar * sidName, - const gchar * sidComposer, const gchar * sidCopyright, - gint loadAddr, gint initAddr, gint playAddr, - gint dataFileLen, const gchar *sidFormat, gint sidModel); -void xs_tuneinfo_free(xs_tuneinfo_t *); +xs_tuneinfo_t *xs_tuneinfo_new(const gchar * pcFilename, + gint nsubTunes, gint startTune, const gchar * sidName, + const gchar * sidComposer, const gchar * sidCopyright, + gint loadAddr, gint initAddr, gint playAddr, + gint dataFileLen, const gchar *sidFormat, gint sidModel); +void xs_tuneinfo_free(xs_tuneinfo_t *); #ifdef __cplusplus
--- a/src/sid/xs_stil.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_stil.c Thu May 22 19:32:39 2008 +0200 @@ -228,7 +228,7 @@ if (subEntry < 1) { XS_STILDB_ERR(lineNum, tmpLine, "Number of subEntry (%i) for '%s' is invalid\n", - subEntry, tmnode->filename); + subEntry, tmnode ? tmnode->filename : ""); subEntry = 0; } } else {
--- a/src/sid/xs_stil.h Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_stil.h Thu May 22 19:32:39 2008 +0200 @@ -10,25 +10,25 @@ /* Types */ typedef struct { - gchar *name, - *author, - *title, - *info; + gchar *name, + *author, + *title, + *info; } stil_subnode_t; typedef struct _stil_node_t { - gchar *filename; - gint nsubTunes; - stil_subnode_t **subTunes; - struct _stil_node_t *prev, *next; + gchar *filename; + gint nsubTunes; + stil_subnode_t **subTunes; + struct _stil_node_t *prev, *next; } stil_node_t; typedef struct { - stil_node_t *nodes, - **pindex; - size_t n; + stil_node_t *nodes, + **pindex; + size_t n; } xs_stildb_t; @@ -37,7 +37,7 @@ gint xs_stildb_read(xs_stildb_t *, gchar *); gint xs_stildb_index(xs_stildb_t *); void xs_stildb_free(xs_stildb_t *); -stil_node_t * xs_stildb_get_node(xs_stildb_t *, gchar *); +stil_node_t * xs_stildb_get_node(xs_stildb_t *, gchar *); #ifdef __cplusplus }
--- a/src/sid/xs_support.h Thu May 22 19:31:48 2008 +0200 +++ b/src/sid/xs_support.h Thu May 22 19:32:39 2008 +0200 @@ -15,7 +15,6 @@ #ifdef AUDACIOUS_PLUGIN #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #else #include <xmms/plugin.h> #include <xmms/util.h>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/Makefile Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,41 @@ +PLUGIN = skins${PLUGIN_SUFFIX} + +SRCS = plugin.c \ + skins_cfg.c \ + pixbuf_effects.c \ + dnd.c \ + ui_fileopener.c \ + ui_skin.c \ + ui_skinned_window.c \ + ui_dock.c \ + util.c \ + ui_vis.c \ + ui_svis.c \ + ui_skinned_menurow.c \ + ui_skinned_button.c \ + ui_skinned_textbox.c \ + ui_skinned_playstatus.c \ + ui_skinned_monostereo.c \ + ui_skinned_number.c \ + ui_skinned_horizontal_slider.c \ + ui_skinned_equalizer_graph.c \ + ui_skinned_equalizer_slider.c \ + ui_skinned_playlist.c \ + ui_skinned_playlist_slider.c \ + ui_main.c \ + ui_equalizer.c \ + ui_playlist.c \ + ui_main_evlisteners.c \ + ui_playlist_evlisteners.c \ + ui_manager.c \ + ui_hints.c \ + icons-stock.c + +include ../../buildsys.mk +include ../../extra.mk + +plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR} + +CFLAGS += ${PLUGIN_CFLAGS} ${BEEP_DEFINES} +CPPFLAGS += ${PLUGIN_CPPFLAGS} ${MOWGLI_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${PANGO_CFLAGS} ${CAIRO_CFLAGS} ${PANGOCAIRO_CFLAGS} ${XRENDER_CFLAGS} ${XCOMPOSITE_CFLAGS} -I../.. +LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${PANGO_LIBS} ${CAIRO_LIBS} ${PANGOCAIRO_LIBS} ${XRENDER_LIBS} ${XCOMPOSITE_LIBS} ${MOWGLI_LIBS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/actions-equalizer.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,38 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_ACTIONS_EQUALIZER_H +#define AUDACIOUS_ACTIONS_EQUALIZER_H + +void action_equ_load_preset(void); +void action_equ_load_auto_preset(void); +void action_equ_load_default_preset(void); +void action_equ_zero_preset(void); +void action_equ_load_preset_file(void); +void action_equ_load_preset_eqf(void); +void action_equ_import_winamp_presets(void); +void action_equ_save_preset(void); +void action_equ_save_auto_preset(void); +void action_equ_save_default_preset(void); +void action_equ_save_preset_file(void); +void action_equ_save_preset_eqf(void); +void action_equ_delete_preset(void); +void action_equ_delete_auto_preset(void); + +#endif /* AUDACIOUS_ACTIONS_EQUALIZER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/actions-mainwin.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,76 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_ACTIONS_MAINWIN_H +#define AUDACIOUS_ACTIONS_MAINWIN_H + +#include <glib.h> +#include <gtk/gtk.h> + +/* actions below are handled in mainwin.c */ + + +/* toggle actions */ +void action_anamode_peaks(GtkToggleAction*); +void action_autoscroll_songname(GtkToggleAction*); +void action_playback_noplaylistadvance(GtkToggleAction*); +void action_playback_repeat(GtkToggleAction*); +void action_playback_shuffle(GtkToggleAction*); +void action_stop_after_current_song(GtkToggleAction*); +void action_view_always_on_top(GtkToggleAction*); +void action_view_scaled(GtkToggleAction*); +void action_view_easymove(GtkToggleAction*); +void action_view_on_all_workspaces(GtkToggleAction*); +void action_roll_up_equalizer(GtkToggleAction*); +void action_roll_up_player(GtkToggleAction*); +void action_roll_up_playlist_editor(GtkToggleAction*); +void action_show_equalizer(GtkToggleAction*); +void action_show_player(GtkToggleAction*); +void action_show_playlist_editor(GtkToggleAction*); + +/* radio actions (one for each radio action group) */ +void action_anafoff(GtkAction*,GtkRadioAction*); +void action_anamode(GtkAction*,GtkRadioAction*); +void action_anatype(GtkAction*,GtkRadioAction*); +void action_peafoff(GtkAction*,GtkRadioAction*); +void action_refrate(GtkAction*,GtkRadioAction*); +void action_scomode(GtkAction*,GtkRadioAction*); +void action_vismode(GtkAction*,GtkRadioAction*); +void action_vprmode(GtkAction*,GtkRadioAction*); +void action_wshmode(GtkAction*,GtkRadioAction*); +void action_viewtime(GtkAction*,GtkRadioAction*); + +/* normal actions */ +void action_about_audacious(void); +void action_ab_clear(void); +void action_ab_set(void); +void action_jump_to_file(void); +void action_jump_to_playlist_start(void); +void action_jump_to_time(void); +void action_play_file(void); +void action_play_location(void); +void action_playback_next(void); +void action_playback_pause(void); +void action_playback_play(void); +void action_playback_previous(void); +void action_playback_stop(void); +void action_preferences(void); +void action_quit(void); +void action_current_track_info(void); +#endif /* AUDACIOUS_ACTIONS_MAINWIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/actions-playlist.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,74 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_ACTIONS_PLAYLIST_H +#define AUDACIOUS_ACTIONS_PLAYLIST_H + +void action_playlist_load_list(void); +void action_playlist_save_list(void); +void action_playlist_save_default_list(void); +void action_playlist_refresh_list(void); +void action_open_list_manager(void); + +void action_playlist_prev(void); +void action_playlist_new(void); +void action_playlist_next(void); +void action_playlist_delete(void); + +void action_playlist_search_and_select(void); +void action_playlist_invert_selection(void); +void action_playlist_select_all(void); +void action_playlist_select_none(void); + +void action_playlist_clear_queue(void); +void action_playlist_remove_unavailable(void); +void action_playlist_remove_dupes_by_title(void); +void action_playlist_remove_dupes_by_filename(void); +void action_playlist_remove_dupes_by_full_path(void); +void action_playlist_remove_all(void); +void action_playlist_remove_selected(void); +void action_playlist_remove_unselected(void); + +/* void action_playlist_add_cd(void); - this is no longer needed, as the respective menu entry is added from within the cdaudio plugin */ +void action_playlist_add_url(void); +void action_playlist_add_files(void); + +void action_playlist_randomize_list(void); +void action_playlist_reverse_list(void); + +void action_playlist_sort_by_title(void); +void action_playlist_sort_by_artist(void); +void action_playlist_sort_by_filename(void); +void action_playlist_sort_by_full_path(void); +void action_playlist_sort_by_date(void); +void action_playlist_sort_by_track_number(void); +void action_playlist_sort_by_playlist_entry(void); + +void action_playlist_sort_selected_by_title(void); +void action_playlist_sort_selected_by_artist(void); +void action_playlist_sort_selected_by_filename(void); +void action_playlist_sort_selected_by_full_path(void); +void action_playlist_sort_selected_by_date(void); +void action_playlist_sort_selected_by_track_number(void); +void action_playlist_sort_selected_by_playlist_entry(void); + +void action_playlist_track_info(void); +void action_queue_toggle(void); + +#endif /* AUDACIOUS_ACTIONS_PLAYLIST_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/debug.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,44 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include <glib.h> + +#ifdef NDEBUG + +/* void REQUIRE_LOCK(GMutex *m); */ +# define REQUIRE_LOCK(m) + +/* void REQUIRE_STR_UTF8(const gchar *str); */ +# define REQUIRE_STR_UTF8(str) + +/* void REQUIRE_STATIC_LOCK(GStaticMutex *m); */ +# define REQUIRE_STATIC_LOCK(m) + +#else /* !NDEBUG */ + +/* void REQUIRE_LOCK(GMutex *m); */ +# define REQUIRE_LOCK(m) G_STMT_START { \ + if (g_mutex_trylock(m)) { \ + g_critical(G_STRLOC ": Mutex not locked!"); \ + g_mutex_unlock(m); \ + } \ + } G_STMT_END + +/* void REQUIRE_STATIC_LOCK(GStaticMutex *m); */ +# define REQUIRE_STATIC_LOCK(m) G_STMT_START { \ + if (G_TRYLOCK(m)) { \ + g_critical(G_STRLOC ": Mutex not locked!"); \ + G_UNLOCK(m); \ + } \ + } G_STMT_END + +/* void REQUIRE_STR_UTF8(const gchar *str); */ +# define REQUIRE_STR_UTF8(str) G_STMT_START { \ + if (!g_utf_validate(str, -1, NULL)) \ + g_warning(G_STRLOC ": String is not UTF-8!"); \ + } G_STMT_END + +#endif /* NDEBUG */ + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/dnd.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,34 @@ +/* Audacious + * Copyright (C) 2005-2007 Audacious development team. + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "dnd.h" + +void +aud_drag_dest_set(GtkWidget *widget) +{ + gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + aud_drop_types, 5, + GDK_ACTION_COPY | GDK_ACTION_MOVE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/dnd.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,51 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_DND_H +#define AUDACIOUS_DND_H + +#include <gtk/gtk.h> + +/* Designate dropped data types that we know and care about */ +enum { + BMP_DROP_STRING, + BMP_DROP_PLAINTEXT, + BMP_DROP_URLENCODED, + BMP_DROP_SKIN, + BMP_DROP_FONT +}; + +/* Drag data format listing for gtk_drag_dest_set() */ +static const GtkTargetEntry aud_drop_types[] = { + {"text/plain", 0, BMP_DROP_PLAINTEXT}, + {"text/uri-list", 0, BMP_DROP_URLENCODED}, + {"STRING", 0, BMP_DROP_STRING}, + {"interface/x-winamp-skin", 0, BMP_DROP_SKIN}, + {"application/x-font-ttf", 0, BMP_DROP_FONT}, +}; + +void aud_drag_dest_set(GtkWidget*); + +#endif /* AUDACIOUS_DND_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/icons-stock.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,61 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2008 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + + +#include "icons-stock.h" +#include "plugin.h" +#include <gdk/gdk.h> +#include <gtk/gtk.h> + + +static void +load_stock_icon(gchar *id, gchar *filename, GtkIconFactory *iconfactory) +{ + GtkIconSet *iconset; + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + if (pixbuf == NULL) + return; + + iconset = gtk_icon_set_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + + gtk_icon_factory_add(iconfactory, id, iconset); +} + +void +register_aud_stock_icons(void) +{ + GtkIconFactory *iconfactory = gtk_icon_factory_new(); + + load_stock_icon(AUD_STOCK_PLAYLIST, + DATA_DIR "/images/menu_playlist.png", iconfactory); + load_stock_icon(AUD_STOCK_PLUGIN, + DATA_DIR "/images/menu_plugin.png", iconfactory); + load_stock_icon(AUD_STOCK_QUEUETOGGLE, + DATA_DIR "/images/menu_queue_toggle.png", iconfactory); + load_stock_icon(AUD_STOCK_RANDOMIZEPL, + DATA_DIR "/images/menu_randomize_playlist.png", iconfactory); + + + gtk_icon_factory_add_default( iconfactory ); + g_object_unref( iconfactory ); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/icons-stock.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,32 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_ICONS_STOCK_H +#define AUDACIOUS_ICONS_STOCK_H + +void register_aud_stock_icons(void); + +/* this header contains macro defines for Audacious stock icons */ + +#define AUD_STOCK_PLAYLIST "aud-playlist" +#define AUD_STOCK_PLUGIN "aud-plugin" +#define AUD_STOCK_QUEUETOGGLE "aud-queuetoggle" +#define AUD_STOCK_RANDOMIZEPL "aud-randomizepl" + +#endif /* AUDACIOUS_ICONS_STOCK_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/images/audacious_eq.xpm Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,93 @@ +/* XPM */ +static char *audacious_eq_icon[] = { +/* columns rows colors chars-per-pixel */ +"48 48 39 1", +" c #e36d45", +". c #e3734d", +"X c #e47650", +"o c #e57a54", +"O c #e57d59", +"+ c #e6805d", +"@ c #e68462", +"# c #e78867", +"$ c #e88665", +"% c #e88866", +"& c #e88b6b", +"* c #e98f70", +"= c #e99274", +"- c #ea9678", +"; c #ea997c", +": c #eb9d82", +"> c #eca086", +", c #eda48b", +"< c #eda88f", +"1 c #eeab93", +"2 c #efae98", +"3 c #efb09a", +"4 c #f0b29c", +"5 c #f0b5a0", +"6 c #f2bba7", +"7 c #f2bca9", +"8 c #f3c5b4", +"9 c #f4c7b8", +"0 c #f4cabb", +"q c #f5cec0", +"w c #f6d6cb", +"e c #f7d8ce", +"r c #f7dad0", +"t c #f8dcd3", +"y c #f8e0d7", +"u c #f9e3db", +"i c #fae6e0", +"p c #fae8e2", +"a c white", +/* pixels */ +"<2211111<<<<,,:,,:::::::::::-=---=====&=&&&=&&&&", +"255544422211111<<<<<<::::::::::----======&&&&&##", +"25554442222111<<,<,,:<:::::::------===&=*&&&%%$&", +"1544442222111<<<<<<:<:<:::::-:----=====&*&&&&%$%", +"2554442221111<<<:<:<::<::::::----=====&=&&%&$%%#", +"154442222111<<,<,,<:<::::-:-----====&&=&&&&&%$@$", +"14422222111<<<,,,:<<:::::::-:----====&&&&&&%%$@%", +"1442222211<<<<,,:<:::::::--:=--===&==&&&&&%%$@@%", +"1442221211<<<,,,,<,:::::-:----=-====&&&&&$$$$@@@", +"124222111<<<,,,,::::::;::-:---===*=&=&&&&&%@@@@#", +"1422211111<<<,,,,:::::;;-:----===&=&&&&&$$$#@@@@", +"12222111<taaaaa4,:::::::---=======&=&&&&%$$@@@+@", +"<222111<<taaaaa4::::::-----=-====&&&&&&&$$#@+@+@", +"<2211111<taaaaa4,::::--::---==**=&&&&&$%$#@@@++@", +"<21211<<<taaaaa3:::::::----====*=&&&&%%%$@@+@+O@", +"<21211<<<taaaaa3::::-:---=====**&&&&&%%$@@@@+++@", +"<111<<<<<taaaaa3::::;;----*-*=&&&&&&#%$$@@@+++O+", +"<111<<<,,raaaaa3:::;;;---*-*==*&&&&&%%$@@@@+++++", +",1111<<,,raaaaa2::;;-----111111&&&&%%$#@@@+++OO+", +"<11<<<<,<raaaaa2;;;;;---:aaaaap&&&%%$$@@@+++OOO+", +",8ppppi8>raaaaa3:;;;--*-;aaaaap&&%&$$$@@++@OOOOO", +",qaaaaa0,raaaaa1;;;----=-aaaaap&&%#$@@@+@+O+OOO+", +",qaaaaa0,raaaaa2;;;---==;aaaaap&&%%$#@@@OO+OOooO", +",qaaaaa0>eaaaaa1;;---===-aaaaap&%%$$@++@++OOOOo+", +",0aaaaa0,eaaaaa1;;----==-aaaaap#&$$#@@+++OOOOooO", +",0aaaaa0>raaaaa1-;--====-aaaaap#:ttttt7++OOooooO", +",qaaaaa0:taaaaa1--;==***-aaaaap$,aaaaaq+OOOooooO", +":0aaaaa9:eaaaaa1-wuuuuu&-aaaaap$,aaaaaq+OOOooo.O", +",0aaaaa0:eaaaaa1-paaaaa==aaaaap$,aaaaaqOOOooo.oO", +":0aaaaa9:eaaaaa1=paaaaa&=aaaaap@,aaaaaqOOOoooo.O", +":qaaaaa9:waaaaa1-paaaaa=-aaaaap@>aaaaaqOoOoooXXO", +":0aaaaa9:waaaaa1=paaaaa&*aaaaap@,aaaaa0O;77777*o", +">0aaaaa9:eaaaaa1=paaaaa&=aaaaap@>aaaaaqO4aaaaa3o", +":0aaaaa8;eaaaaa,-paaaaa&=aaaaai@>aaaaaqo4aaaaa3o", +":0aaaaa8;eaaaaa,=paaaaa&=aaaaap+>aaaaa0O5aaaaa3o", +":9aaaaa9;eaaaaa<*paaaaa&&aaaaai@>aaaaaqo4aaaaa3o", +":0aaaaa8;eaaaaa,&paaaaa&=aaaaap+>aaaaa0o4aaaaa2o", +":9aaaaa8-eaaaaa,=paaaaa%&aaaaau+:aaaaa0o4aaaaa2X", +":9aaaaa8;waaaaa,=paaaaa%=aaaaai+>aaaaa0o4aaaaa2X", +":9aaaaa8-eaaaaa,&paaaaa#&aaaaai+:aaaaa0o4aaaaa3X", +";8aaaaa8-waaaaa,*paaaaa#*aaaaapO:aaaaa0o3aaaaa2X", +";8aaaaa8-waaaaa,*paaaaa#&aaaaaiO:aaaaa0X3aaaaa2.", +";9aaaaa8-waaaaa>&paaaaa@&aaaaaiO:aaaaa0X3aaaaa1o", +";9aaaaa8=eaaaaa,&paaaaa@&aaaaauO:aaaaa0.3aaaaa1.", +";8aaaaa8*waaaaa:&paaaaa@&aaaaauO:aaaaa0.2aaaaa1.", +";8aaaaa8=waaaaa>&paaaaa@&aaaaaiO;aaaaa0.3aaaaa2.", +";;;;;=====***&*&#&###@@+++OOOOOooXoX..... . .", +"---=--====*****&&&&#####@@@@++++OOOOOooooXXX...o" +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/images/audacious_playlist.xpm Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,97 @@ +/* XPM */ +static char *audacious_playlist_icon[] = { +/* columns rows colors chars-per-pixel */ +"48 48 43 1", +" c #e36e45", +". c #e3734c", +"X c #e47650", +"o c #e57a54", +"O c #e57d59", +"+ c #e6815d", +"@ c #e68462", +"# c #e78867", +"$ c #e88665", +"% c #e88866", +"& c #e88b6b", +"* c #e98f70", +"= c #e99273", +"- c #ea9679", +"; c #eb997c", +": c #eb9d82", +"> c #eca086", +", c #eda48b", +"< c #eda88f", +"1 c #eeaa93", +"2 c #efae98", +"3 c #efb09a", +"4 c #f0b29c", +"5 c #f0b5a1", +"6 c #f0b8a5", +"7 c #f1bcaa", +"8 c #f2c0ae", +"9 c #f3c3b3", +"0 c #f4c7b8", +"q c #f4cabb", +"w c #f5cec1", +"e c #f5d1c4", +"r c #f6d5c9", +"t c #f7d8cd", +"y c #f8ddd4", +"u c #f8e0d7", +"i c #f9e3db", +"p c #fae6e0", +"a c #fae8e2", +"s c #fcf0eb", +"d c #fcf4f1", +"f c #fdf9f7", +"g c white", +/* pixels */ +"<22111111<<<<,,,::,:::::;;;;;;----====*=&=&&&&#&", +"2555444423111<<<<<<,,>>>:>:;;;;;---====**&&&&&#&", +"25444424312111<<<,,,,>,>>:::;;;----===&==&&&%%%#", +"1554442222111<<<,,,,,>:::::;;;----=====&&&&&%%%#", +"25544422211111<<,,,,::>::;;;;;---=====**&&&%%%$#", +"19aat22uaaaapppppppppppipppiiipiiiiiu4*&4iuuue$$", +"19ggi22sggggggggggggggggggggggggggggg7*&7ggggp%$", +"10ggi24dggggggggggggggggggggggggggggg7*&7ggggp@#", +"17trq21errreeeeeewwwwwwwqwqqq0qq00000,&&,99993@$", +"1333221111<<<,,,,,>::::;;;;-;--===***&&%##$#$@@@", +"1432211111<<<,,,>>>>:::;;;;---===***&&&&####$@@@", +"<9aar11upaappppppipipiiiiiiiu5===***&&&%2uyyyw+@", +"<0ggu11dggggggggggggggggggggg9=&=&&*&&%%7ggggp@@", +"10ggu11dggggggggggggggggggggg9===&&&&&%%7ggggp+@", +"<39961<6766666665554544442222:&=**&&&#%%=,,>>;O@", +"<11111<<<<<,,>::::::;;----=====&*&&&&%%$@@@@++++", +"<1111<<1<,,>,>::::;;;-;----=*=&&&&&%%%$$@@@+++O@", +"<0ggy<<sgggggggggggggggggggggggggggs%%$$6ggggpO+", +"<9ggy<<sgggggggggggggggggggggggggggs%%$@6ggggpO+", +",9ggy<<sgggggggggggggggggggggggggggs%%$@6ggggiO+", +",2774<,,,,>:>:::;;;----====&&&&&&%%%$$$+@+++OOO+", +",111<<,,>>>>::::;;;---=-===&=&&&%#%%$@@+++++OOO+", +",<<<,,,6665555545444422112111111<#$$@@@@&:>;;-OO", +",9ggy,,fggggggggggggggggggggggggd$$$@@+@6ggggpoO", +",9ggy,:fggggggggggggggggggggggggf$$@@@++6ggggpoO", +",7ggy,,fggggggggggggggggggggggggd$$@@+@+5ggggioO", +"><<,,,:,>::::;;;---=====&&&&&%%%$$@@+@++OOOooooO", +":<,,>,>::::;;;;----====&&=&&&%%%$@@@@OOOOOOooo.O", +":1664,:65535444442121211<11<1<,,,,>>,&+O&:;;;-oO", +",7ggy><gggggggggggggggggggggggggggggg6OO5ggggp.O", +":6ggu:,gggggggggggggggggggggggggggggg3OO5ggggi.o", +":5ppe:,ippiiiiiiiiiuiiuiuuuuuuyyyyuyy1Oo<yyyy0Xo", +">,,:::::::;;----====&&&&&%%%$$@@++++OOOOoooXXX.o", +":,,::::::;;;;--=-==***&%&&&%%$@@@+++OOOooooo.X.o", +":1ww9:<qqqqqq000000000099,%%@@@@+++OOoOo-76662.o", +":6ggy:1gggggggggggggggggg7$$@@@+++OOOOoo4ggggi.o", +":6ggy:2gggggggggggggggggg6%@@@++++OOOOoo4ggggi.X", +":2ppw:1iiiiiiiiuuiuiuuuiu2@@@@+++OOOoooo,yyyy0.o", +";::::;;;;--======&=&&&%%%$$@+@+++OOOoooo.X.... X", +";,::;;;;----=====&&&&%#$$$@@@+++OOOoOoo.o... ..X", +";1wq7;1qqq0q0000900999999979979777777;oo-66661 o", +";5ggy;5gggggggggggggggggggggggggggggg3..3ggggi .", +";5ggy;6gggggggggggggggggggggggggggggg2o.3ggggi X", +"-1wq7;<q0q000000099999979779777777777-X.=66561 .", +";;;:=;-====**=&&&&#%#$@@@@+++OOOOoooo..o.... .", +";;;;;;=-====*&&&&&#%$$@@++++OOOOooooo..... .", +";;;-;-====***&*&&###$@@@++O+OOOooo.o.... .. .", +"----=-======&=&&&#&##$$$@@@@+++OOOOOOoooo.o....o" +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/pixbuf_effects.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,88 @@ +/* + * Audacious + * Copyright (c) 2006-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include <glib.h> + +#include "platform/smartinclude.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> + +static GdkPixbuf * +create_new_pixbuf (GdkPixbuf *src) +{ + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + + return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + gdk_pixbuf_get_has_alpha (src), + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); +} + +GdkPixbuf * +audacious_create_colorized_pixbuf (GdkPixbuf *src, + int red_value, + int green_value, + int blue_value) +{ + int i, j; + int width, height, has_alpha, src_row_stride, dst_row_stride; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + GdkPixbuf *dest; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest = create_new_pixbuf (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + src_row_stride = gdk_pixbuf_get_rowstride (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) { + pixdest = target_pixels + i*dst_row_stride; + pixsrc = original_pixels + i*src_row_stride; + for (j = 0; j < width; j++) { + *pixdest++ = (*pixsrc++ * red_value) >> 8; + *pixdest++ = (*pixsrc++ * green_value) >> 8; + *pixdest++ = (*pixsrc++ * blue_value) >> 8; + if (has_alpha) { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/platform/smartinclude.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006-2007 William Pitcock <nenolod -at- nenolod.net> + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include <gdk/gdk.h> + +#ifdef GDK_WINDOWING_X11 +# include <gdk/gdkx.h> +#endif + +#ifdef GDK_WINDOWING_WIN32 +# include <gdk/gdkwin32.h> +#endif + +#include <gdk/gdkkeysyms.h> + +#ifdef GDK_WINDOWING_QUARTZ +# include <Carbon/Carbon.h> +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,98 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2008 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + + +#include "plugin.h" +#include "skins_cfg.h" +#include "ui_skin.h" +#include "ui_skinned_window.h" +#include "ui_manager.h" +#include "icons-stock.h" +#include <audacious/i18n.h> +#include <libintl.h> + +#define PACKAGE "audacious-plugins" + +GeneralPlugin skins_gp = +{ + .description= "Audacious Skinned GUI", + .init = skins_init, + .about = skins_about, + .configure = skins_configure, + .cleanup = skins_cleanup +}; + +GeneralPlugin *skins_gplist[] = { &skins_gp, NULL }; +SIMPLE_GENERAL_PLUGIN(skins, skins_gplist); +GtkWidget *mainwin; +gboolean plugin_is_active = FALSE; + +void skins_init(void) { + plugin_is_active = TRUE; + g_log_set_handler(NULL, G_LOG_LEVEL_WARNING, g_log_default_handler, NULL); + + skins_cfg_load(); + + register_aud_stock_icons(); + ui_manager_init(); + ui_manager_create_menus(); + mainwin_setup_menus(); + + init_skins(config.skin); + + mainwin_real_show(); + + return; +} + +void skins_cleanup(void) { + if (plugin_is_active == TRUE) { + skins_cfg_free(); + gtk_widget_destroy(mainwin); + gtk_widget_destroy(equalizerwin); + skin_destroy(aud_active_skin); + aud_active_skin = NULL; + mainwin = NULL; + equalizerwin = NULL; + plugin_is_active = FALSE; + } + + return; +} + + +void skins_configure(void) { + return; +} + +void skins_about(void) { + static GtkWidget* about_window = NULL; + + if (about_window) { + gtk_window_present(GTK_WINDOW(about_window)); + return; + } + + about_window = audacious_info_dialog(_("About Skinned GUI"), + _("Copyright (c) 2008, by Tomasz Moń <desowin@gmail.com>\n\n"), + _("OK"), FALSE, NULL, NULL); + + g_signal_connect(G_OBJECT(about_window), "destroy", G_CALLBACK(gtk_widget_destroyed), &about_window); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/plugin.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,37 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2008 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef PLUGIN_SKINS_H +#define PLUGIN_SKINS_H + +#include <glib.h> +#include <audacious/plugin.h> +#include "skins_cfg.h" +#include "ui_main.h" +#include "ui_equalizer.h" + +#define PACKAGE_NAME "audacious-plugins" + +void skins_init(void); +void skins_cleanup(void); +void skins_configure(void); +void skins_about(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/skins_cfg.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,228 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2008 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + + +#include "skins_cfg.h" +#include "ui_skin.h" +#include "ui_vis.h" +#include <glib.h> +#include <stdlib.h> +#include <audacious/plugin.h> + +skins_cfg_t config; + +skins_cfg_t skins_default_config = { + .scaled = FALSE, + .autoscroll = TRUE, + .always_on_top = FALSE, + .sticky = FALSE, + .scale_factor = 2.0, + .always_show_cb = TRUE, + .close_dialog_open = TRUE, + .close_dialog_add = TRUE, + .skin = NULL, + .filesel_path = NULL, + .playlist_visible = FALSE, + .equalizer_visible = FALSE, + .player_visible = TRUE, + .player_shaded = FALSE, + .equalizer_shaded = FALSE, + .playlist_shaded = FALSE, + .dim_titlebar = TRUE, + .show_wm_decorations = FALSE, + .easy_move = TRUE, + .allow_broken_skins = FALSE, + .warn_about_broken_gtk_engines = TRUE, + .warn_about_win_visibility = TRUE, + .disable_inline_gtk = FALSE, + .timer_mode = 0, + .vis_type = VIS_ANALYZER, + .analyzer_mode = ANALYZER_NORMAL, + .analyzer_type = ANALYZER_BARS, + .scope_mode = SCOPE_DOT, + .voiceprint_mode = VOICEPRINT_NORMAL, + .vu_mode = VU_SMOOTH, + .vis_refresh = REFRESH_FULL, + .analyzer_falloff = FALLOFF_FAST, + .peaks_falloff = FALLOFF_SLOW, + .player_x = MAINWIN_DEFAULT_POS_X, + .player_y = MAINWIN_DEFAULT_POS_Y, + .equalizer_x = EQUALIZER_DEFAULT_POS_X, + .equalizer_y = EQUALIZER_DEFAULT_POS_Y, + .playlist_x = PLAYLISTWIN_DEFAULT_POS_X, + .playlist_y = PLAYLISTWIN_DEFAULT_POS_Y, + .playlist_width = PLAYLISTWIN_DEFAULT_WIDTH, + .playlist_height = PLAYLISTWIN_DEFAULT_HEIGHT, + .playlist_position = 0, + .mouse_change = 8, /* mouse wheel scroll step */ + .scroll_pl_by = 3, + .colorize_r = 255, .colorize_g = 255, .colorize_b = 255, + .snap_distance = 10, + .snap_windows = TRUE, + .save_window_position = TRUE, + .analyzer_peaks = TRUE, + .twoway_scroll = TRUE, /* use back and forth scroll */ + .mainwin_use_bitmapfont = TRUE, + .eq_scaled_linked = TRUE, + .use_xmms_style_fileselector = FALSE, + .show_numbers_in_pl = TRUE, + .show_separator_in_pl = TRUE, +}; + +typedef struct skins_cfg_boolent_t { + char const *be_vname; + gboolean *be_vloc; + gboolean be_wrt; +} skins_cfg_boolent; + +static skins_cfg_boolent skins_boolents[] = { + {"always_show_cb", &config.always_show_cb, TRUE}, + {"always_on_top", &config.always_on_top, TRUE}, + {"sticky", &config.sticky, TRUE}, + {"always_show_cb", &config.always_show_cb, TRUE}, + {"scaled", &config.scaled, TRUE}, + {"autoscroll_songname", &config.autoscroll, TRUE}, + {"equalizer_visible", &config.equalizer_visible, TRUE}, + {"playlist_visible", &config.playlist_visible, TRUE}, + {"player_visible", &config.player_visible, TRUE}, + {"player_shaded", &config.player_shaded, TRUE}, + {"equalizer_shaded", &config.equalizer_shaded, TRUE}, + {"playlist_shaded", &config.playlist_shaded, TRUE}, + {"dim_titlebar", &config.dim_titlebar, TRUE}, + {"show_wm_decorations", &config.show_wm_decorations, TRUE}, + {"easy_move", &config.easy_move, TRUE}, + {"allow_broken_skins", &config.allow_broken_skins, TRUE}, + {"disable_inline_gtk", &config.disable_inline_gtk, TRUE}, + {"snap_windows", &config.snap_windows, TRUE}, + {"save_window_positions", &config.save_window_position, TRUE}, + {"analyzer_peaks", &config.analyzer_peaks, TRUE}, + {"twoway_scroll", &config.twoway_scroll, TRUE}, + {"warn_about_win_visibility", &config.warn_about_win_visibility, TRUE}, + {"warn_about_broken_gtk_engines", &config.warn_about_broken_gtk_engines, TRUE}, + {"mainwin_use_bitmapfont", &config.mainwin_use_bitmapfont, TRUE}, + {"eq_scaled_linked", &config.eq_scaled_linked, TRUE}, + {"show_numbers_in_pl", &config.show_numbers_in_pl, TRUE}, + {"show_separator_in_pl", &config.show_separator_in_pl, TRUE}, +}; + +static gint ncfgbent = G_N_ELEMENTS(skins_boolents); + +typedef struct skins_cfg_nument_t { + char const *ie_vname; + gint *ie_vloc; + gboolean ie_wrt; +} skins_cfg_nument; + +static skins_cfg_nument skins_numents[] = { + {"player_x", &config.player_x, TRUE}, + {"player_y", &config.player_y, TRUE}, + {"timer_mode", &config.timer_mode, TRUE}, + {"vis_type", &config.vis_type, TRUE}, + {"analyzer_mode", &config.analyzer_mode, TRUE}, + {"analyzer_type", &config.analyzer_type, TRUE}, + {"scope_mode", &config.scope_mode, TRUE}, + {"vu_mode", &config.vu_mode, TRUE}, + {"voiceprint_mode", &config.voiceprint_mode, TRUE}, + {"vis_refresh_rate", &config.vis_refresh, TRUE}, + {"analyzer_falloff", &config.analyzer_falloff, TRUE}, + {"peaks_falloff", &config.peaks_falloff, TRUE}, + {"playlist_x", &config.playlist_x, TRUE}, + {"playlist_y", &config.playlist_y, TRUE}, + {"playlist_width", &config.playlist_width, TRUE}, + {"playlist_height", &config.playlist_height, TRUE}, + {"playlist_position", &config.playlist_position, TRUE}, + {"equalizer_x", &config.equalizer_x, TRUE}, + {"equalizer_y", &config.equalizer_y, TRUE}, + {"mouse_wheel_change", &config.mouse_change, TRUE}, + {"scroll_pl_by", &config.scroll_pl_by, TRUE}, + {"colorize_r", &config.colorize_r, TRUE}, + {"colorize_g", &config.colorize_g, TRUE}, + {"colorize_b", &config.colorize_b, TRUE}, + {"snap_distance", &config.snap_distance, TRUE}, +}; + +static gint ncfgient = G_N_ELEMENTS(skins_numents); + +void skins_cfg_free() { + if (config.skin) { g_free(config.skin); config.skin = NULL; } +} + +void skins_cfg_load() { + mcs_handle_t *cfgfile = aud_cfg_db_open(); + + /* if (!aud_cfg_db_get_int(cfgfile, "skins", "field_name", &(cfg->where))) + cfg->where = default value + if (!aud_cfg_db_get_string(cfgfile, "skins", "field_name", &(cfg->where))) + cfg->where = g_strdup("defaul"); + if (!aud_cfg_db_get_bool(cfgfile, "skins", "field_name", &(cfg->where))) + cfg->where = FALSE / TRUE; + */ + + memcpy(&config, &skins_default_config, sizeof(skins_cfg_t)); + int i; + + for (i = 0; i < ncfgbent; ++i) { + aud_cfg_db_get_bool(cfgfile, "skins", + skins_boolents[i].be_vname, + skins_boolents[i].be_vloc); + } + + for (i = 0; i < ncfgient; ++i) { + aud_cfg_db_get_int(cfgfile, "skins", + skins_numents[i].ie_vname, + skins_numents[i].ie_vloc); + } + + if (!aud_cfg_db_get_string(cfgfile, "skins", "skin", &(config.skin))) + config.skin = g_strdup(BMP_DEFAULT_SKIN_PATH); + + if (!aud_cfg_db_get_float(cfgfile, "skins", "scale_factor", &(config.scale_factor))) + config.scale_factor = 2.0; + + aud_cfg_db_close(cfgfile); +} + + +void skins_cfg_save(skins_cfg_t * cfg) { + mcs_handle_t *cfgfile = aud_cfg_db_open(); + +/* + aud_cfg_db_set_int(cfgfile, "skins", "field_name", cfg->where); + aud_cfg_db_set_string(cfgfile, "skins", "field_name", cfg->where); + aud_cfg_db_set_bool(cfgfile, "skins", "field_name", cfg->where); +*/ + aud_cfg_db_set_string(cfgfile, "skins", "skin", cfg->skin); + + int i; + + for (i = 0; i < ncfgbent; ++i) + if (skins_boolents[i].be_wrt) + aud_cfg_db_set_bool(cfgfile, "skins", + skins_boolents[i].be_vname, + *skins_boolents[i].be_vloc); + + for (i = 0; i < ncfgient; ++i) + if (skins_numents[i].ie_wrt) + aud_cfg_db_set_int(cfgfile, "skins", + skins_numents[i].ie_vname, + *skins_numents[i].ie_vloc); + + aud_cfg_db_close(cfgfile); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/skins_cfg.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,86 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2008 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef SKINS_CFG_H +#define SKINS_CFG_H + +#include <glib.h> + +#define MAINWIN_DEFAULT_POS_X 20 +#define MAINWIN_DEFAULT_POS_Y 20 +#define EQUALIZER_DEFAULT_POS_X 20 +#define EQUALIZER_DEFAULT_POS_Y 136 +#define PLAYLISTWIN_DEFAULT_WIDTH 275 +#define PLAYLISTWIN_DEFAULT_HEIGHT 232 +#define PLAYLISTWIN_DEFAULT_POS_X 295 +#define PLAYLISTWIN_DEFAULT_POS_Y 20 + + +typedef struct { + gint player_x, player_y; + gint equalizer_x, equalizer_y; + gint playlist_x, playlist_y; + gint playlist_width, playlist_height; + gint snap_distance; + gboolean snap_windows, save_window_position; + gboolean scaled, autoscroll; + gboolean always_on_top, sticky; + gfloat scale_factor; + gboolean always_show_cb; + gboolean close_dialog_open; + gboolean close_dialog_add; + gchar *skin; + gchar *filesel_path; + gboolean player_visible, equalizer_visible, playlist_visible; + gboolean player_shaded, equalizer_shaded, playlist_shaded; + gboolean dim_titlebar; + gboolean show_wm_decorations; + gboolean easy_move; + gboolean allow_broken_skins; + gboolean disable_inline_gtk; + gboolean analyzer_peaks; + gboolean twoway_scroll; + gint timer_mode; + gint vis_type; + gint analyzer_mode, analyzer_type; + gint scope_mode; + gint voiceprint_mode; + gint vu_mode, vis_refresh; + gint analyzer_falloff, peaks_falloff; + gint playlist_position; + gint mouse_change; + gint colorize_r; gint colorize_g; gint colorize_b; + gint scroll_pl_by; + gboolean warn_about_win_visibility; + gboolean warn_about_broken_gtk_engines; + gboolean mainwin_use_bitmapfont; + gboolean eq_scaled_linked; + gboolean use_xmms_style_fileselector; + gboolean show_numbers_in_pl, show_separator_in_pl; +} skins_cfg_t; + +extern skins_cfg_t config; + +skins_cfg_t * skins_cfg_new(void); +void skins_cfg_free(); +void skins_cfg_load(); +void skins_cfg_save(); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_dock.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,531 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_dock.h" +#include "skins_cfg.h" +#include <gdk/gdk.h> +#include <stdlib.h> +#include <audacious/plugin.h> +#include "ui_skinned_window.h" + +#include "platform/smartinclude.h" + +static GList *dock_window_list = NULL; + +struct _DockedWindow { + GtkWindow *w; + gint offset_x, offset_y; +}; + +typedef struct _DockedWindow DockedWindow; + + +static gint +docked_list_compare(DockedWindow * a, DockedWindow * b) +{ + if (a->w == b->w) + return 0; + return 1; +} + +static void +snap_edge(gint * x, gint * y, gint w, gint h, gint bx, gint by, + gint bw, gint bh) +{ + gint sd = config.snap_distance; + + if ((*x + w > bx - sd) && (*x + w < bx + sd) && + (*y > by - h - sd) && (*y < by + bh + sd)) { + *x = bx - w; + if ((*y > by - sd) && (*y < by + sd)) + *y = by; + if ((*y + h > by + bh - sd) && (*y + h < by + bh + sd)) + *y = by + bh - h; + } + if ((*x > bx + bw - sd) && (*x < bx + bw + sd) && + (*y > by - h - sd) && (*y < by + bh + sd)) { + *x = bx + bw; + if ((*y > by - sd) && (*y < by + sd)) + *y = by; + if ((*y + h > by + bh - sd) && (*y + h < by + bh + sd)) + *y = by + bh - h; + } +} + +static void +snap(gint * x, gint * y, gint w, gint h, gint bx, gint by, gint bw, gint bh) +{ + snap_edge(x, y, w, h, bx, by, bw, bh); + snap_edge(y, x, h, w, by, bx, bh, bw); +} + +static void +calc_snap_offset(GList * dlist, GList * wlist, gint x, gint y, + gint * off_x, gint * off_y) +{ + gint nx, ny, nw, nh, sx, sy, sw, sh; + GtkWindow *w; + GList *dnode, *wnode; + DockedWindow temp, *dw; + + + *off_x = 0; + *off_y = 0; + + if (!config.snap_windows) + return; + + /* + * FIXME: Why not break out of the loop when we find someting + * to snap to? + */ + for (dnode = dlist; dnode; dnode = g_list_next(dnode)) { + dw = dnode->data; + gtk_window_get_size(dw->w, &nw, &nh); + + nx = dw->offset_x + *off_x + x; + ny = dw->offset_y + *off_y + y; + + /* Snap to screen edges */ + if (abs(nx) < config.snap_distance) + *off_x -= nx; + if (abs(ny) < config.snap_distance) + *off_y -= ny; + if (abs(nx + nw - gdk_screen_width()) < config.snap_distance) + *off_x -= nx + nw - gdk_screen_width(); + if (abs(ny + nh - gdk_screen_height()) < config.snap_distance) + *off_y -= ny + nh - gdk_screen_height(); + + /* Snap to other windows */ + for (wnode = wlist; wnode; wnode = g_list_next(wnode)) { + temp.w = wnode->data; + if (g_list_find_custom + (dlist, &temp, (GCompareFunc) docked_list_compare)) + /* These windows are already docked */ + continue; + + w = GTK_WINDOW(wnode->data); + gtk_window_get_position(w, &sx, &sy); + gtk_window_get_size(w, &sw, &sh); + + nx = dw->offset_x + *off_x + x; + ny = dw->offset_y + *off_y + y; + + snap(&nx, &ny, nw, nh, sx, sy, sw, sh); + + *off_x += nx - (dw->offset_x + *off_x + x); + *off_y += ny - (dw->offset_y + *off_y + y); + } + } +} + + +static gboolean +is_docked(gint a_x, gint a_y, gint a_w, gint a_h, + gint b_x, gint b_y, gint b_w, gint b_h) +{ + if (((a_x == b_x + b_w) || (a_x + a_w == b_x)) && + (b_y + b_h >= a_y) && (b_y <= a_y + a_h)) + return TRUE; + + if (((a_y == b_y + b_h) || (a_y + a_h == b_y)) && + (b_x >= a_x - b_w) && (b_x <= a_x + a_w)) + return TRUE; + + return FALSE; +} + +/* + * Builds a list of all windows that are docked to the window "w". + * Recursively adds all windows that are docked to the windows that are + * docked to "w" and so on... + * FIXME: init_off_? ? + */ + +static GList * +get_docked_list(GList * dlist, GList * wlist, GtkWindow * w, + gint init_off_x, gint init_off_y) +{ + GList *node; + DockedWindow *dwin, temp; + gint w_x, w_y, w_width, w_height; + gint t_x, t_y, t_width, t_height; + + + gtk_window_get_position(w, &w_x, &w_y); + gtk_window_get_size(w, &w_width, &w_height); + if (!dlist) { + dwin = g_new0(DockedWindow, 1); + dwin->w = w; + dlist = g_list_append(dlist, dwin); + } + + for (node = wlist; node; node = g_list_next(node)) { + temp.w = node->data; + if (g_list_find_custom + (dlist, &temp, (GCompareFunc) docked_list_compare)) + continue; + + gtk_window_get_position(GTK_WINDOW(node->data), &t_x, &t_y); + gtk_window_get_size(GTK_WINDOW(node->data), &t_width, &t_height); + if (is_docked + (w_x, w_y, w_width, w_height, t_x, t_y, t_width, t_height)) { + dwin = g_new0(DockedWindow, 1); + dwin->w = node->data; + + dwin->offset_x = t_x - w_x + init_off_x; + dwin->offset_y = t_y - w_y + init_off_y; + + dlist = g_list_append(dlist, dwin); + + dlist = + get_docked_list(dlist, wlist, dwin->w, dwin->offset_x, + dwin->offset_y); + } + } + return dlist; +} + +static void +free_docked_list(GList * dlist) +{ + GList *node; + + for (node = dlist; node; node = g_list_next(node)) + g_free(node->data); + g_list_free(dlist); +} + +static void +docked_list_move(GList * list, gint x, gint y) +{ + GList *node; + DockedWindow *dw; + + for (node = list; node; node = g_list_next(node)) { + dw = node->data; + gtk_window_move(dw->w, x + dw->offset_x, y + dw->offset_y); + + SkinnedWindow *window = SKINNED_WINDOW(dw->w); + if (window) { + switch(window->type) { + + case WINDOW_MAIN: + config.player_x = x + dw->offset_x; + config.player_y = y + dw->offset_y; + break; + case WINDOW_EQ: + config.equalizer_x = x + dw->offset_x; + config.equalizer_y = y + dw->offset_y; + break; + case WINDOW_PLAYLIST: + config.playlist_x = x + dw->offset_x; + config.playlist_y = y + dw->offset_y; + break; + } + + window->x = x + dw->offset_x; + window->y = y + dw->offset_y; + } + } +} + +static GList * +shade_move_list(GList * list, GtkWindow * widget, gint offset) +{ + gint x, y, w, h; + GList *node; + DockedWindow *dw; + + gtk_window_get_position(widget, &x, &y); + gtk_window_get_size(widget, &w, &h); + + + for (node = list; node;) { + gint dx, dy, dwidth, dheight; + + dw = node->data; + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && + ((dx + dwidth) > x && dx < (x + w))) { + list = g_list_remove_link(list, node); + g_list_free_1(node); + + node = list = shade_move_list(list, dw->w, offset); + } + else + node = g_list_next(node); + } + gtk_window_move(widget, x, y + offset); + return list; +} + +/* + * Builds a list of the windows in the list of DockedWindows "winlist" + * that are docked to the top or bottom of the window, and recursively + * adds all windows that are docked to the top or bottom of that window, + * and so on... + * Note: The data in "winlist" is not copied. + */ +static GList * +find_shade_list(GtkWindow * widget, GList * winlist, GList * shade_list) +{ + gint x, y, w, h; + gint dx, dy, dwidth, dheight; + GList *node; + + gtk_window_get_position(widget, &x, &y); + gtk_window_get_size(widget, &w, &h); + for (node = winlist; node; node = g_list_next(node)) { + DockedWindow *dw = node->data; + if (g_list_find_custom + (shade_list, dw, (GCompareFunc) docked_list_compare)) + continue; + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + + /* FIXME. Is the is_docked() necessary? */ + if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && + ((dx + dwidth) > x && dx < (x + w))) { + shade_list = g_list_append(shade_list, dw); + shade_list = find_shade_list(dw->w, winlist, shade_list); + } + } + return shade_list; +} + +void +dock_window_resize(GtkWindow * widget, gint new_w, gint new_h, gint w, gint h) +{ + gdk_window_set_hints(GTK_WIDGET(widget)->window, 0, 0, MIN(w, new_w), + MIN(h, new_h), MAX(w, new_w), MAX(h, new_h), + GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); + gdk_window_resize(GTK_WIDGET(widget)->window, new_w, new_h); + gdk_window_set_hints(GTK_WIDGET(widget)->window, 0, 0, new_w, new_h, + new_w, new_h, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); +} + +void +dock_shade(GList * window_list, GtkWindow * widget, gint new_h) +{ + gint x, y, w, h, off_y, orig_off_y; + GList *node, *docked_list, *slist; + DockedWindow *dw; + + gtk_window_get_position(widget, &x, &y); + gtk_window_get_size(widget, &w, &h); + + if (config.show_wm_decorations) { + dock_window_resize(widget, w, new_h, w, h); + return; + } + + docked_list = get_docked_list(NULL, window_list, widget, 0, 0); + slist = find_shade_list(widget, docked_list, NULL); + + off_y = new_h - h; + do { + orig_off_y = off_y; + for (node = slist; node; node = g_list_next(node)) { + gint dx, dy, dwidth, dheight; + + dw = node->data; + if (dw->w == widget) + continue; + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + if ((dy >= y) && ((dy + off_y + dheight) > gdk_screen_height())) + off_y -= (dy + off_y + dheight) - gdk_screen_height(); + else if ((dy >= y) && ((dy + dheight) == gdk_screen_height())) + off_y = 0; + + if (((dy >= y) && ((dy + off_y) < 0))) + off_y -= dy + off_y; + if ((dy < y) && ((dy + (off_y - (new_h - h))) < 0)) + off_y -= dy + (off_y - (new_h - h)); + } + } while (orig_off_y != off_y); + if (slist) { + GList *mlist = g_list_copy(slist); + + /* Remove this widget from the list */ + for (node = mlist; node; node = g_list_next(node)) { + dw = node->data; + if (dw->w == widget) { + mlist = g_list_remove_link(mlist, node); + g_list_free_1(node); + break; + } + } + for (node = mlist; node;) { + GList *temp; + gint dx, dy, dwidth, dheight; + + dw = node->data; + + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + /* + * Find windows that are directly docked to this window, + * move it, and any windows docked to that window again + */ + if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && + ((dx + dwidth) > x && dx < (x + w))) { + mlist = g_list_remove_link(mlist, node); + g_list_free_1(node); + if (dy > y) + temp = shade_move_list(mlist, dw->w, off_y); + else if (off_y - (new_h - h) != 0) + temp = shade_move_list(mlist, dw->w, off_y - (new_h - h)); + else + temp = mlist; + node = mlist = temp; + } + else + node = g_list_next(node); + } + g_list_free(mlist); + } + g_list_free(slist); + free_docked_list(docked_list); + gtk_window_move(widget, x, y + off_y - (new_h - h)); + dock_window_resize(widget, w, new_h, w, h); +} + +void +dock_move_press(GList * window_list, GtkWindow * w, + GdkEventButton * event, gboolean move_list) +{ + gint mx, my; + DockedWindow *dwin; + + if (config.show_wm_decorations) + return; + + gtk_window_present(w); + mx = event->x; + my = event->y; + gtk_object_set_data(GTK_OBJECT(w), "move_offset_x", GINT_TO_POINTER(mx)); + gtk_object_set_data(GTK_OBJECT(w), "move_offset_y", GINT_TO_POINTER(my)); + if (move_list) + gtk_object_set_data(GTK_OBJECT(w), "docked_list", + get_docked_list(NULL, window_list, w, 0, 0)); + else { + dwin = g_new0(DockedWindow, 1); + dwin->w = w; + gtk_object_set_data(GTK_OBJECT(w), "docked_list", + g_list_append(NULL, dwin)); + } + gtk_object_set_data(GTK_OBJECT(w), "window_list", window_list); + gtk_object_set_data(GTK_OBJECT(w), "is_moving", GINT_TO_POINTER(1)); +} + +void +dock_move_motion(GtkWindow * w, GdkEventMotion * event) +{ + gint offset_x, offset_y, x, y; + GList *dlist; + GList *window_list; + + if (!gtk_object_get_data(GTK_OBJECT(w), "is_moving")) + return; + + offset_x = + GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(w), "move_offset_x")); + offset_y = + GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(w), "move_offset_y")); + dlist = gtk_object_get_data(GTK_OBJECT(w), "docked_list"); + window_list = gtk_object_get_data(GTK_OBJECT(w), "window_list"); + + x = event->x_root - offset_x; + y = event->y_root - offset_y; + + calc_snap_offset(dlist, window_list, x, y, &offset_x, &offset_y); + x += offset_x; + y += offset_y; + + docked_list_move(dlist, x, y); +} + +void +dock_move_release(GtkWindow * w) +{ + GList *dlist; + gtk_object_remove_data(GTK_OBJECT(w), "is_moving"); + gtk_object_remove_data(GTK_OBJECT(w), "move_offset_x"); + gtk_object_remove_data(GTK_OBJECT(w), "move_offset_y"); + if ((dlist = gtk_object_get_data(GTK_OBJECT(w), "docked_list")) != NULL) + free_docked_list(dlist); + gtk_object_remove_data(GTK_OBJECT(w), "docked_list"); + gtk_object_remove_data(GTK_OBJECT(w), "window_list"); +} + +gboolean +dock_is_moving(GtkWindow * w) +{ + if (gtk_object_get_data(GTK_OBJECT(w), "is_moving")) + return TRUE; + return FALSE; +} + +GList * +dock_add_window(GList * list, GtkWindow * window) +{ + return g_list_append(list, window); +} + +GList * +dock_remove_window(GList * list, GtkWindow * window) +{ + return g_list_remove(list, window); +} + +GList * +dock_window_set_decorated(GList * list, GtkWindow * window, + gboolean decorated) +{ + if (gtk_window_get_decorated(window) == decorated) + return list; + + if (decorated) + list = dock_remove_window(list, window); + else + list = dock_add_window(list, window); + + gtk_window_set_decorated(window, decorated); + + return list; +} + +GList * +get_dock_window_list() { + return dock_window_list; +} + +void +set_dock_window_list(GList * list) { + dock_window_list = list; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_dock.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,50 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef DOCK_H +#define DOCK_H + +#include <glib.h> +#include <gtk/gtk.h> + +void dock_set_uposition(GtkWindow * widget, gint x, gint y); +GList *dock_add_window(GList * window_list, GtkWindow * window); +GList *dock_remove_window(GList * window_list, GtkWindow * window); +void dock_move_press(GList * window_list, GtkWindow * w, + GdkEventButton * event, gboolean move_list); +void dock_move_motion(GtkWindow * w, GdkEventMotion * event); +void dock_move_release(GtkWindow * w); +void dock_get_widget_pos(GtkWindow * w, gint * x, gint * y); +gboolean dock_is_moving(GtkWindow * w); +void dock_shade(GList * window_list, GtkWindow * widget, gint new_h); + +GList *dock_window_set_decorated(GList * list, GtkWindow * window, + gboolean decorated); +void dock_window_resize(GtkWindow * widget, gint new_w, gint new_h, gint w, gint h); + +GList *get_dock_window_list(); +void set_dock_window_list(GList * list); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_equalizer.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,1539 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +/*#define AUD_DEBUG*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui_equalizer.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <stdio.h> +#include <math.h> +#include <string.h> + +#include "platform/smartinclude.h" +#include "ui_skin.h" +#include "ui_manager.h" +#include "actions-equalizer.h" +#include "util.h" +#include "ui_main.h" +#include <audacious/plugin.h> + +#include "images/audacious_eq.xpm" + +#include "ui_dock.h" +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_horizontal_slider.h" +#include "ui_skinned_equalizer_slider.h" +#include "ui_skinned_equalizer_graph.h" +#include "skins_cfg.h" + +enum PresetViewCols { + PRESET_VIEW_COL_NAME, + PRESET_VIEW_N_COLS +}; + +struct _EqualizerPreset { + gchar *name; + gfloat preamp, bands[10]; +}; + +typedef struct _EqualizerPreset EqualizerPreset; + + +GtkWidget *equalizerwin; +GtkWidget *equalizerwin_graph; + +static GtkWidget *equalizerwin_load_window = NULL; +static GtkWidget *equalizerwin_load_auto_window = NULL; +static GtkWidget *equalizerwin_save_window = NULL; +static GtkWidget *equalizerwin_save_entry = NULL; +static GtkWidget *equalizerwin_save_auto_window = NULL; +static GtkWidget *equalizerwin_save_auto_entry = NULL; +static GtkWidget *equalizerwin_delete_window = NULL; +static GtkWidget *equalizerwin_delete_auto_window = NULL; + +static GtkWidget *equalizerwin_on, *equalizerwin_auto; + +static GtkWidget *equalizerwin_close, *equalizerwin_presets, *equalizerwin_shade; +static GtkWidget *equalizerwin_preamp,*equalizerwin_bands[10]; +static GtkWidget *equalizerwin_volume, *equalizerwin_balance; + +static GList *equalizer_presets = NULL, *equalizer_auto_presets = NULL; + +EqualizerPreset * +equalizer_preset_new(const gchar * name) +{ + EqualizerPreset *preset = g_new0(EqualizerPreset, 1); + preset->name = g_strdup(name); + return preset; +} + +void +equalizer_preset_free(EqualizerPreset * preset) +{ + if (!preset) + return; + + g_free(preset->name); + g_free(preset); +} + +void +equalizerwin_set_scaled(gboolean ds) +{ + gint height; + + if (config.equalizer_shaded) + height = 14; + else + height = 116; + + if (config.scaled) { + dock_window_resize(GTK_WINDOW(equalizerwin), 275 * config.scale_factor, + height * config.scale_factor, 275 * config.scale_factor, height * config.scale_factor); + } else { + dock_window_resize(GTK_WINDOW(equalizerwin), 275, height, 275, height); + } + + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(equalizerwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + g_signal_emit_by_name(child, "toggle-scaled"); + } + gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + config.equalizer_shaded), 0, 0); +} + +void +equalizerwin_set_shade_menu_cb(gboolean shaded) +{ + config.equalizer_shaded = shaded; + + if (shaded) { + dock_shade(get_dock_window_list(), GTK_WINDOW(equalizerwin), + 14 * EQUALIZER_SCALE_FACTOR); + ui_skinned_set_push_button_data(equalizerwin_shade, -1, 3, -1, 47); + ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); + ui_skinned_set_push_button_data(equalizerwin_close, 11, 38, 11, 47); + ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQ_EX); + gtk_widget_show(equalizerwin_volume); + gtk_widget_show(equalizerwin_balance); + } + else { + dock_shade(get_dock_window_list(), GTK_WINDOW(equalizerwin), + 116 * EQUALIZER_SCALE_FACTOR); + ui_skinned_set_push_button_data(equalizerwin_shade, -1, 137, -1, 38); + ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQMAIN); + ui_skinned_set_push_button_data(equalizerwin_close, 0, 116, 0, 125); + ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQMAIN); + gtk_widget_hide(equalizerwin_volume); + gtk_widget_hide(equalizerwin_balance); + } + + gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + config.equalizer_shaded), 0, 0); +} + +static void +equalizerwin_set_shade(gboolean shaded) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "roll up equalizer" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); +} + +static void +equalizerwin_shade_toggle(void) +{ + equalizerwin_set_shade(!config.equalizer_shaded); +} + +void +equalizerwin_eq_changed(void) +{ + gint i; + + aud_cfg->equalizer_preamp = ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); + for (i = 0; i < 10; i++) + aud_cfg->equalizer_bands[i] = ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]); + /* um .. i think we need both of these for xmms compatibility .. + not sure. -larne */ +#if 0 + input_set_eq(aud_cfg->equalizer_active, aud_cfg->equalizer_preamp, + aud_cfg->equalizer_bands); + output_set_eq(aud_cfg->equalizer_active, aud_cfg->equalizer_preamp, + aud_cfg->equalizer_bands); +#endif + gtk_widget_queue_draw(equalizerwin_graph); +} + +static void +equalizerwin_on_pushed(void) +{ + aud_cfg->equalizer_active = UI_SKINNED_BUTTON(equalizerwin_on)->inside; + equalizerwin_eq_changed(); +} + +static void +equalizerwin_presets_pushed(void) +{ + GdkModifierType modmask; + gint x, y; + + gdk_window_get_pointer(NULL, &x, &y, &modmask); + ui_manager_popup_menu_show(GTK_MENU(equalizerwin_presets_menu), x, y, 1, GDK_CURRENT_TIME); +} + +static void +equalizerwin_auto_pushed(void) +{ + aud_cfg->equalizer_autoload = UI_SKINNED_BUTTON(equalizerwin_auto)->inside; +} + +gboolean +equalizerwin_press(GtkWidget * widget, GdkEventButton * event, + gpointer callback_data) +{ + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS + && event->y < 14) { + equalizerwin_set_shade(!config.equalizer_shaded); + if (dock_is_moving(GTK_WINDOW(equalizerwin))) + dock_move_release(GTK_WINDOW(equalizerwin)); + return TRUE; + } + if (event->button == 3) { + /* + * Pop up the main menu a few pixels down to avoid + * anything to be selected initially. + */ + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root, + event->y_root + 2, 3, event->time); + return TRUE; + } + + return FALSE; +} + +static gboolean +equalizerwin_keypress(GtkWidget * widget, + GdkEventKey * event, + gpointer data) +{ +#if 0 + if (event->keyval == GDK_Tab && event->state & GDK_CONTROL_MASK) { + if (config.playlist_visible) + gtk_window_present(GTK_WINDOW(playlistwin)); + else if (config.player_visible) + gtk_window_present(GTK_WINDOW(mainwin)); + return TRUE; + } +#endif + if (!config.equalizer_shaded) { + gtk_widget_event(mainwin, (GdkEvent *) event); + return TRUE; + } + + switch (event->keyval) { + case GDK_Left: + case GDK_KP_Left: + mainwin_set_balance_diff(-4); + break; + case GDK_Right: + case GDK_KP_Right: + mainwin_set_balance_diff(4); + break; + default: + gtk_widget_event(mainwin, (GdkEvent *) event); + break; + } + + return FALSE; +} + +static void +equalizerwin_close_cb(void) +{ + equalizerwin_show(FALSE); +} + +static gboolean +equalizerwin_delete(GtkWidget * widget, + gpointer data) +{ + equalizerwin_show(FALSE); + return TRUE; +} + +static GList * +equalizerwin_read_presets(const gchar * basename) +{ +#if 0 + gchar *filename, *name; + RcFile *rcfile; + GList *list = NULL; + gint i, p = 0; + EqualizerPreset *preset; + + /* START mod: add check for the default presets locate in system path ({prefix}/share/audacious) + by Massimo Cavalleri (submax) */ + + filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL); + + if ((rcfile = aud_rcfile_open(filename)) == NULL) { + g_free(filename); + // DATA_DIR = "{prefix}/share/audacious" ; example is "/usr/share/audacious" + filename = g_build_filename(DATA_DIR, basename, NULL); + if ((rcfile = aud_rcfile_open(filename)) == NULL) { + g_free(filename); + return NULL; + } + } + + // END mod + + g_free(filename); + + for (;;) { + gchar section[21]; + + g_snprintf(section, sizeof(section), "Preset%d", p++); + if (aud_rcfile_read_string(rcfile, "Presets", section, &name)) { + preset = g_new0(EqualizerPreset, 1); + preset->name = name; + aud_rcfile_read_float(rcfile, name, "Preamp", &preset->preamp); + for (i = 0; i < 10; i++) { + gchar band[7]; + g_snprintf(band, sizeof(band), "Band%d", i); + aud_rcfile_read_float(rcfile, name, band, &preset->bands[i]); + } + list = g_list_prepend(list, preset); + } + else + break; + } + list = g_list_reverse(list); + aud_rcfile_free(rcfile); + return list; +#endif +} + +gint +equalizerwin_volume_frame_cb(gint pos) +{ + if (equalizerwin_volume) { + gint x; + if (pos < 32) + x = 1; + else if (pos < 63) + x = 4; + else + x = 7; + + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_volume)->knob_nx = x; + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_volume)->knob_px = x; + } + return 1; +} + +static void +equalizerwin_volume_motion_cb(GtkWidget *widget, gint pos) +{ + gint v = (gint) rint(pos * 100 / 94.0); + mainwin_adjust_volume_motion(v); + mainwin_set_volume_slider(v); +} + +static void +equalizerwin_volume_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_volume_release(); +} + +static gint +equalizerwin_balance_frame_cb(gint pos) +{ + if (equalizerwin_balance) { + gint x; + if (pos < 13) + x = 11; + else if (pos < 26) + x = 14; + else + x = 17; + + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_balance)->knob_nx = x; + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_balance)->knob_px = x; + } + + return 1; +} + +static void +equalizerwin_balance_motion_cb(GtkWidget *widget, gint pos) +{ + gint b; + pos = MIN(pos, 38); /* The skin uses a even number of pixels + for the balance-slider *sigh* */ + b = (gint) rint((pos - 19) * 100 / 19.0); + mainwin_adjust_balance_motion(b); + mainwin_set_balance_slider(b); +} + +static void +equalizerwin_balance_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_balance_release(); +} + +void +equalizerwin_set_balance_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(equalizerwin_balance, + (gint) rint((percent * 19 / 100.0) + 19)); +} + +void +equalizerwin_set_volume_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(equalizerwin_volume, + (gint) rint(percent * 94 / 100.0)); +} + +static void +equalizerwin_create_widgets(void) +{ + gint i; + + equalizerwin_on = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(equalizerwin_on, SKINNED_WINDOW(equalizerwin)->fixed, + 14, 18, 25, 12, 10, 119, 128, 119, 69, 119, 187, 119, SKIN_EQMAIN); + g_signal_connect(equalizerwin_on, "clicked", equalizerwin_on_pushed, NULL); + UI_SKINNED_BUTTON(equalizerwin_on)->inside = aud_cfg->equalizer_active; + + equalizerwin_auto = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(equalizerwin_auto, SKINNED_WINDOW(equalizerwin)->fixed, + 39, 18, 33, 12, 35, 119, 153, 119, 94, 119, 212, 119, SKIN_EQMAIN); + g_signal_connect(equalizerwin_auto, "clicked", equalizerwin_auto_pushed, NULL); + UI_SKINNED_BUTTON(equalizerwin_auto)->inside = aud_cfg->equalizer_autoload; + + equalizerwin_presets = ui_skinned_button_new(); + ui_skinned_push_button_setup(equalizerwin_presets, SKINNED_WINDOW(equalizerwin)->fixed, + 217, 18, 44, 12, 224, 164, 224, 176, SKIN_EQMAIN); + g_signal_connect(equalizerwin_presets, "clicked", equalizerwin_presets_pushed, NULL ); + + equalizerwin_close = ui_skinned_button_new(); + ui_skinned_push_button_setup(equalizerwin_close, SKINNED_WINDOW(equalizerwin)->fixed, + 264, 3, 9, 9, 0, 116, 0, 125, SKIN_EQMAIN); + g_signal_connect(equalizerwin_close, "clicked", equalizerwin_close_cb, NULL ); + + equalizerwin_shade = ui_skinned_button_new(); + ui_skinned_push_button_setup(equalizerwin_shade, SKINNED_WINDOW(equalizerwin)->fixed, + 254, 3, 9, 9, 254, 137, 1, 38, SKIN_EQMAIN); + ui_skinned_button_set_skin_index2(equalizerwin_shade, SKIN_EQ_EX); + g_signal_connect(equalizerwin_shade, "clicked", equalizerwin_shade_toggle, NULL ); + + equalizerwin_graph = ui_skinned_equalizer_graph_new(SKINNED_WINDOW(equalizerwin)->fixed, 86, 17); + + equalizerwin_preamp = ui_skinned_equalizer_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, 21, 38); + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, aud_cfg->equalizer_preamp); + + for (i = 0; i < 10; i++) { + equalizerwin_bands[i] = + ui_skinned_equalizer_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, 78 + (i * 18), 38); + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], aud_cfg->equalizer_bands[i]); + } + + equalizerwin_volume = + ui_skinned_horizontal_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, + 61, 4, 97, 8, 1, 30, 1, 30, 3, 7, 4, 61, 0, 94, + equalizerwin_volume_frame_cb, SKIN_EQ_EX); + g_signal_connect(equalizerwin_volume, "motion", G_CALLBACK(equalizerwin_volume_motion_cb), NULL); + g_signal_connect(equalizerwin_volume, "release", G_CALLBACK(equalizerwin_volume_release_cb), NULL); + + + equalizerwin_balance = + ui_skinned_horizontal_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, + 164, 4, 42, 8, 11, 30, 11, 30, 3, 7, 4, 164, 0, 39, + equalizerwin_balance_frame_cb, SKIN_EQ_EX); + g_signal_connect(equalizerwin_balance, "motion", G_CALLBACK(equalizerwin_balance_motion_cb), NULL); + g_signal_connect(equalizerwin_balance, "release", G_CALLBACK(equalizerwin_balance_release_cb), NULL); +} + + +static void +equalizerwin_create_window(void) +{ + GdkPixbuf *icon; + gint width, height; + + width = 275; + height = config.equalizer_shaded ? 14 : 116; + + equalizerwin = ui_skinned_window_new("equalizer"); + gtk_window_set_title(GTK_WINDOW(equalizerwin), _("Audacious Equalizer")); + gtk_window_set_role(GTK_WINDOW(equalizerwin), "equalizer"); + gtk_window_set_resizable(GTK_WINDOW(equalizerwin), FALSE); + + if (config.scaled && config.eq_scaled_linked) { + width *= config.scale_factor; + height *= config.scale_factor; + } + + gtk_widget_set_size_request(equalizerwin, width, height); + + /* this will hide only mainwin. it's annoying! yaz */ + gtk_window_set_transient_for(GTK_WINDOW(equalizerwin), + GTK_WINDOW(mainwin)); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(equalizerwin), TRUE); + + icon = gdk_pixbuf_new_from_xpm_data((const gchar **) audacious_eq_icon); + gtk_window_set_icon(GTK_WINDOW(equalizerwin), icon); + g_object_unref(icon); + + gtk_widget_set_app_paintable(equalizerwin, TRUE); + + if (config.equalizer_x != -1 && config.save_window_position) + gtk_window_move(GTK_WINDOW(equalizerwin), + config.equalizer_x, config.equalizer_y); + + g_signal_connect(equalizerwin, "delete_event", + G_CALLBACK(equalizerwin_delete), NULL); + g_signal_connect(equalizerwin, "button_press_event", + G_CALLBACK(equalizerwin_press), NULL); + g_signal_connect(equalizerwin, "key_press_event", + G_CALLBACK(equalizerwin_keypress), NULL); +} + +void +equalizerwin_create(void) +{ + equalizer_presets = equalizerwin_read_presets("eq.preset"); + equalizer_auto_presets = equalizerwin_read_presets("eq.auto_preset"); + + equalizerwin_create_window(); + + gtk_window_add_accel_group( GTK_WINDOW(equalizerwin) , ui_manager_get_accel_group() ); + + equalizerwin_create_widgets(); +} + + +void +equalizerwin_show(gboolean show) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "show equalizer" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , show ); + + if (show) + equalizerwin_real_show(); + else + equalizerwin_real_hide(); +} + +void +equalizerwin_real_show(void) +{ + gtk_window_move(GTK_WINDOW(equalizerwin), config.equalizer_x, config.equalizer_y); + if (config.scaled && config.eq_scaled_linked) + gtk_widget_set_size_request(equalizerwin, 275 * config.scale_factor, + ((config.equalizer_shaded ? 14 : 116) * config.scale_factor)); + else + gtk_widget_set_size_request(equalizerwin, 275, + (config.equalizer_shaded ? 14 : 116)); + config.equalizer_visible = TRUE; + UI_SKINNED_BUTTON(mainwin_eq)->inside = TRUE; + gtk_widget_show_all(equalizerwin); + + if (!config.equalizer_shaded) { + gtk_widget_hide(equalizerwin_volume); + gtk_widget_hide(equalizerwin_balance); + } + else { + ui_skinned_set_push_button_data(equalizerwin_shade, -1, 3, -1, 47); + ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); + ui_skinned_set_push_button_data(equalizerwin_close, 11, 38, 11, 47); + ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQ_EX); + } + + gtk_window_present(GTK_WINDOW(equalizerwin)); +} + +void +equalizerwin_real_hide(void) +{ + /* + * This function should only be called from the + * main menu signal handler + */ + gtk_widget_hide(equalizerwin); + config.equalizer_visible = FALSE; + UI_SKINNED_BUTTON(mainwin_eq)->inside = FALSE; + gtk_widget_queue_draw(mainwin_eq); +} + +static EqualizerPreset * +equalizerwin_find_preset(GList * list, const gchar * name) +{ + GList *node = list; + EqualizerPreset *preset; + + while (node) { + preset = node->data; + if (!strcasecmp(preset->name, name)) + return preset; + node = g_list_next(node); + } + return NULL; +} + +static void +equalizerwin_write_preset_file(GList * list, const gchar * basename) +{ +#if 0 + gchar *filename, *tmp; + gint i, p; + EqualizerPreset *preset; + RcFile *rcfile; + GList *node; + + rcfile = aud_rcfile_new(); + p = 0; + for (node = list; node; node = g_list_next(node)) { + preset = node->data; + tmp = g_strdup_printf("Preset%d", p++); + aud_rcfile_write_string(rcfile, "Presets", tmp, preset->name); + g_free(tmp); + aud_rcfile_write_float(rcfile, preset->name, "Preamp", + preset->preamp); + for (i = 0; i < 10; i++) { + tmp = g_strdup_printf("Band%d\n", i); + aud_rcfile_write_float(rcfile, preset->name, tmp, + preset->bands[i]); + g_free(tmp); + } + } + + filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL); + aud_rcfile_write(rcfile, filename); + aud_rcfile_free(rcfile); + g_free(filename); +#endif +} + +static gboolean +equalizerwin_load_preset(GList * list, const gchar * name) +{ + EqualizerPreset *preset; + gint i; + + if ((preset = equalizerwin_find_preset(list, name)) != NULL) { + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, preset->preamp); + for (i = 0; i < 10; i++) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], preset->bands[i]); + equalizerwin_eq_changed(); + return TRUE; + } + return FALSE; +} + +static GList * +equalizerwin_save_preset(GList * list, const gchar * name, + const gchar * filename) +{ + gint i; + EqualizerPreset *preset; + + if (!(preset = equalizerwin_find_preset(list, name))) { + preset = g_new0(EqualizerPreset, 1); + preset->name = g_strdup(name); + list = g_list_append(list, preset); + } + + preset->preamp = ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); + for (i = 0; i < 10; i++) + preset->bands[i] = ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]); + + equalizerwin_write_preset_file(list, filename); + + return list; +} + +static GList * +equalizerwin_delete_preset(GList * list, gchar * name, gchar * filename) +{ + EqualizerPreset *preset; + GList *node; + + if (!(preset = equalizerwin_find_preset(list, name))) + return list; + + if (!(node = g_list_find(list, preset))) + return list; + + list = g_list_remove_link(list, node); + equalizer_preset_free(preset); + g_list_free_1(node); + + equalizerwin_write_preset_file(list, filename); + + return list; +} + +static void +equalizerwin_delete_selected_presets(GtkTreeView *view, gchar *filename) +{ + gchar *text; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeModel *model = gtk_tree_view_get_model(view); + + /* + * first we are making a list of the selected rows, then we convert this + * list into a list of GtkTreeRowReferences, so that when you delete an + * item you can still access the other items + * finally we iterate through all GtkTreeRowReferences, convert them to + * GtkTreeIters and delete those one after the other + */ + + GList *list = gtk_tree_selection_get_selected_rows(selection, &model); + GList *rrefs = NULL; + GList *litr; + + for (litr = list; litr; litr = litr->next) + { + GtkTreePath *path = litr->data; + rrefs = g_list_append(rrefs, gtk_tree_row_reference_new(model, path)); + } + + for (litr = rrefs; litr; litr = litr->next) + { + GtkTreeRowReference *ref = litr->data; + GtkTreePath *path = gtk_tree_row_reference_get_path(ref); + GtkTreeIter iter; + gtk_tree_model_get_iter(model, &iter, path); + + gtk_tree_model_get(model, &iter, 0, &text, -1); + + if (!strcmp(filename, "eq.preset")) + equalizer_presets = equalizerwin_delete_preset(equalizer_presets, text, filename); + else if (!strcmp(filename, "eq.auto_preset")) + equalizer_auto_presets = equalizerwin_delete_preset(equalizer_auto_presets, text, filename); + + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + } +} + +static GList * +import_winamp_eqf(VFSFile * file) +{ +#if 0 + gchar header[31]; + gchar bands[11]; + gint i = 0; + EqualizerPreset *preset = NULL; + GList *list = NULL; + GtkWidget *dialog; + gchar *realfn; + gchar preset_name[0xb4]; + + vfs_fread(header, 1, 31, file); + if (strncmp(header, "Winamp EQ library file v1.1", 27)) goto error; + + AUDDBG("The EQF header is OK\n"); + + if (vfs_fseek(file, 0x1f, SEEK_SET) == -1) goto error; + + while (vfs_fread(preset_name, 1, 0xb4, file) == 0xb4) { + AUDDBG("The preset name is '%s'\n", preset_name); + vfs_fseek(file, 0x4d, SEEK_CUR); /* unknown crap --asphyx */ + if (vfs_fread(bands, 1, 11, file) != 11) break; + + preset = equalizer_preset_new(preset_name); + /*this was divided by 63, but shouldn't it be 64? --majeru*/ + preset->preamp = EQUALIZER_MAX_GAIN - ((bands[10] * EQUALIZER_MAX_GAIN * 2) / 64.0); + + for (i = 0; i < 10; i++) + preset->bands[i] = EQUALIZER_MAX_GAIN - ((bands[i] * EQUALIZER_MAX_GAIN * 2) / 64.0); + + list = g_list_prepend(list, preset); + } + + list = g_list_reverse(list); + if (list == NULL) goto error; + + return list; + +error: + realfn = g_filename_from_uri(file->uri, NULL, NULL); + dialog = gtk_message_dialog_new (GTK_WINDOW(mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error importing Winamp EQF file '%s'"), + realfn); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_free(realfn); + return NULL; +#endif +} + +static void +free_cb (gpointer data, gpointer user_data) +{ + equalizer_preset_free((EqualizerPreset*)data); +} + +static void +equalizerwin_read_winamp_eqf(VFSFile * file) +{ + GList *presets; + gint i; + + if ((presets = import_winamp_eqf(file)) == NULL) + return; + + /* just get the first preset --asphyx */ + EqualizerPreset *preset = (EqualizerPreset*)presets->data; + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, + preset->preamp); + + for (i = 0; i < 10; i++) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], + preset->bands[i]); + + g_list_foreach(presets, free_cb, NULL); + g_list_free(presets); + + equalizerwin_eq_changed(); +} +#if 0 +static void +equalizerwin_read_aud_preset(RcFile * rcfile) +{ + gfloat val; + gint i; + + if (aud_rcfile_read_float(rcfile, "Equalizer preset", "Preamp", &val)) + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, val); + for (i = 0; i < 10; i++) { + gchar tmp[7]; + g_snprintf(tmp, sizeof(tmp), "Band%d", i); + if (aud_rcfile_read_float(rcfile, "Equalizer preset", tmp, &val)) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], val); + } + equalizerwin_eq_changed(); +} +#endif + +static void +equalizerwin_save_ok(GtkWidget * widget, gpointer data) +{ + const gchar *text; + + text = gtk_entry_get_text(GTK_ENTRY(equalizerwin_save_entry)); + if (strlen(text) != 0) + equalizer_presets = + equalizerwin_save_preset(equalizer_presets, text, "eq.preset"); + gtk_widget_destroy(equalizerwin_save_window); +} + +static void +equalizerwin_save_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + gchar *text; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_entry), text); + equalizerwin_save_ok(NULL, NULL); + + g_free(text); + } + } +} + +static void +equalizerwin_load_ok(GtkWidget *widget, gpointer data) +{ + gchar *text; + + GtkTreeView* view = GTK_TREE_VIEW(data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + equalizerwin_load_preset(equalizer_presets, text); + + g_free(text); + } + } + gtk_widget_destroy(equalizerwin_load_window); +} + +static void +equalizerwin_load_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + equalizerwin_load_ok(NULL, treeview); +} + +static void +equalizerwin_delete_delete(GtkWidget *widget, gpointer data) +{ + equalizerwin_delete_selected_presets(GTK_TREE_VIEW(data), "eq.preset"); +} + +static void +equalizerwin_save_auto_ok(GtkWidget *widget, gpointer data) +{ + const gchar *text; + + text = gtk_entry_get_text(GTK_ENTRY(equalizerwin_save_auto_entry)); + if (strlen(text) != 0) + equalizer_auto_presets = + equalizerwin_save_preset(equalizer_auto_presets, text, + "eq.auto_preset"); + gtk_widget_destroy(equalizerwin_save_auto_window); +} + +static void +equalizerwin_save_auto_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + gchar *text; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), text); + equalizerwin_save_auto_ok(NULL, NULL); + + g_free(text); + } + } +} + +static void +equalizerwin_load_auto_ok(GtkWidget *widget, gpointer data) +{ + gchar *text; + + GtkTreeView *view = GTK_TREE_VIEW(data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + equalizerwin_load_preset(equalizer_auto_presets, text); + + g_free(text); + } + } + gtk_widget_destroy(equalizerwin_load_auto_window); +} + +static void +equalizerwin_load_auto_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + equalizerwin_load_auto_ok(NULL, treeview); +} + +static void +equalizerwin_delete_auto_delete(GtkWidget *widget, gpointer data) +{ + equalizerwin_delete_selected_presets(GTK_TREE_VIEW(data), "eq.auto_preset"); +} + + +static void +load_preset_file(const gchar *filename) +{ +#if 0 + RcFile *rcfile; + + if ((rcfile = aud_rcfile_open(filename)) != NULL) { + equalizerwin_read_aud_preset(rcfile); + aud_rcfile_free(rcfile); + } +#endif +} + +static VFSFile * +open_vfs_file(const gchar *filename, const gchar *mode) +{ + VFSFile *file; + GtkWidget *dialog; + + if (!(file = vfs_fopen(filename, mode))) { + dialog = gtk_message_dialog_new (GTK_WINDOW (mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Error loading file '%s'", + filename); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + + return file; +} + +static void +load_winamp_file(const gchar * filename) +{ +#if 0 + VFSFile *file; + + if (!(file = open_vfs_file(filename, "rb"))) + return; + + equalizerwin_read_winamp_eqf(file); + vfs_fclose(file); +#endif +} + +static void +import_winamp_file(const gchar * filename) +{ +#if 0 + VFSFile *file; + GList *list; + + if (!(file = open_vfs_file(filename, "rb")) || + !(list = import_winamp_eqf(file))) + return; + + equalizer_presets = g_list_concat(equalizer_presets, list); + equalizerwin_write_preset_file(equalizer_presets, "eq.preset"); + + vfs_fclose(file); +#endif +} + +static void +save_preset_file(const gchar * filename) +{ +#if 0 + RcFile *rcfile; + gint i; + + rcfile = aud_rcfile_new(); + aud_rcfile_write_float(rcfile, "Equalizer preset", "Preamp", + ui_skinned_equalizer_slider_get_position(equalizerwin_preamp)); + + for (i = 0; i < 10; i++) { + gchar tmp[7]; + g_snprintf(tmp, sizeof(tmp), "Band%d", i); + aud_rcfile_write_float(rcfile, "Equalizer preset", tmp, + ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i])); + } + + aud_rcfile_write(rcfile, filename); + aud_rcfile_free(rcfile); +#endif +} + +static void +save_winamp_file(const gchar * filename) +{ +#if 0 + VFSFile *file; + + gchar name[257]; + gint i; + guchar bands[11]; + + if (!(file = open_vfs_file(filename, "wb"))) + return; + + vfs_fwrite("Winamp EQ library file v1.1\x1a!--", 1, 31, file); + + memset(name, 0, 257); + g_strlcpy(name, "Entry1", 257); + vfs_fwrite(name, 1, 257, file); + + for (i = 0; i < 10; i++) + bands[i] = 63 - (((ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]) + EQUALIZER_MAX_GAIN) * 63) / EQUALIZER_MAX_GAIN / 2); + bands[10] = 63 - (((ui_skinned_equalizer_slider_get_position(equalizerwin_preamp) + EQUALIZER_MAX_GAIN) * 63) / EQUALIZER_MAX_GAIN / 2); + vfs_fwrite(bands, 1, 11, file); + + vfs_fclose(file); +#endif +} + +static GtkWidget * +equalizerwin_create_list_window(GList *preset_list, + const gchar *title, + GtkWidget **window, + GtkSelectionMode sel_mode, + GtkWidget **entry, + const gchar *action_name, + GCallback action_func, + GCallback select_row_func) +{ + GtkWidget *vbox, *scrolled_window, *bbox, *view; + GtkWidget *button_cancel, *button_action; + GList *node; + + GtkListStore *store; + GtkTreeIter iter; + GtkTreeModel *model; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GtkTreeSortable *sortable; + + + + *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(*window), title); + gtk_window_set_type_hint(GTK_WINDOW(*window), GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_default_size(GTK_WINDOW(*window), 350, 300); + gtk_window_set_position(GTK_WINDOW(*window), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(*window), 10); + gtk_window_set_transient_for(GTK_WINDOW(*window), + GTK_WINDOW(equalizerwin)); + g_signal_connect(*window, "destroy", + G_CALLBACK(gtk_widget_destroyed), window); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(*window), vbox); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + + + /* fill the store with the names of all available presets */ + store = gtk_list_store_new(1, G_TYPE_STRING); + for (node = preset_list; node; node = g_list_next(node)) + { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, ((EqualizerPreset*)node->data)->name, + -1); + } + model = GTK_TREE_MODEL(store); + + + sortable = GTK_TREE_SORTABLE(store); + gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING); + + + view = gtk_tree_view_new(); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, + _("Presets"), renderer, + "text", 0, NULL); + gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); + g_object_unref(model); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, sel_mode); + + + + + gtk_container_add(GTK_CONTAINER(scrolled_window), view); + gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); + + if (entry) { + *entry = gtk_entry_new(); + g_signal_connect(*entry, "activate", action_func, NULL); + gtk_box_pack_start(GTK_BOX(vbox), *entry, FALSE, FALSE, 0); + } + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + button_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + g_signal_connect_swapped(button_cancel, "clicked", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(*window)); + gtk_box_pack_start(GTK_BOX(bbox), button_cancel, TRUE, TRUE, 0); + + button_action = gtk_button_new_from_stock(action_name); + g_signal_connect(button_action, "clicked", G_CALLBACK(action_func), view); + GTK_WIDGET_SET_FLAGS(button_action, GTK_CAN_DEFAULT); + + if (select_row_func) + g_signal_connect(view, "row-activated", G_CALLBACK(select_row_func), NULL); + + + gtk_box_pack_start(GTK_BOX(bbox), button_action, TRUE, TRUE, 0); + + gtk_widget_grab_default(button_action); + + + gtk_widget_show_all(*window); + + return *window; +} + +void +equalizerwin_load_auto_preset(const gchar * filename) +{ +#if 0 + gchar *presetfilename, *directory; + RcFile *rcfile; + + g_return_if_fail(filename != NULL); + + if (!aud_cfg->equalizer_autoload) + return; + + presetfilename = g_strconcat(filename, ".", aud_cfg->eqpreset_extension, NULL); + + /* First try to find a per file preset file */ + if (strlen(aud_cfg->eqpreset_extension) > 0 && + (rcfile = aud_rcfile_open(presetfilename)) != NULL) { + g_free(presetfilename); + equalizerwin_read_aud_preset(rcfile); + aud_rcfile_free(rcfile); + return; + } + + g_free(presetfilename); + + directory = g_path_get_dirname(filename); + presetfilename = g_build_filename(directory, aud_cfg->eqpreset_default_file, + NULL); + g_free(directory); + + /* Try to find a per directory preset file */ + if (strlen(aud_cfg->eqpreset_default_file) > 0 && + (rcfile = aud_rcfile_open(presetfilename)) != NULL) { + equalizerwin_read_aud_preset(rcfile); + aud_rcfile_free(rcfile); + } + else if (!equalizerwin_load_preset + (equalizer_auto_presets, g_basename(filename))) { + /* Fall back to the oldstyle auto presets */ + equalizerwin_load_preset(equalizer_presets, "Default"); + } + + g_free(presetfilename); +#endif +} + +void +equalizerwin_set_preamp(gfloat preamp) +{ + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, preamp); + equalizerwin_eq_changed(); +} + +void +equalizerwin_set_band(gint band, gfloat value) +{ + g_return_if_fail(band >= 0 && band < 10); + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[band], value); +} + +gfloat +equalizerwin_get_preamp(void) +{ + return ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); +} + +gfloat +equalizerwin_get_band(gint band) +{ + g_return_val_if_fail(band >= 0 && band < 10, 0.0); + return ui_skinned_equalizer_slider_get_position(equalizerwin_bands[band]); +} + +void +action_equ_load_preset(void) +{ + if (equalizerwin_load_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_load_window)); + return; + } + + equalizerwin_create_list_window(equalizer_presets, + Q_("Load preset"), + &equalizerwin_load_window, + GTK_SELECTION_SINGLE, NULL, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_load_ok), + G_CALLBACK(equalizerwin_load_select)); +} + +void +action_equ_load_auto_preset(void) +{ + if (equalizerwin_load_auto_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_load_auto_window)); + return; + } + + equalizerwin_create_list_window(equalizer_auto_presets, + Q_("Load auto-preset"), + &equalizerwin_load_auto_window, + GTK_SELECTION_SINGLE, NULL, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_load_auto_ok), + G_CALLBACK(equalizerwin_load_auto_select)); +} + +void +action_equ_load_default_preset(void) +{ + equalizerwin_load_preset(equalizer_presets, "Default"); +} + +void +action_equ_zero_preset(void) +{ + gint i; + + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, 0); + for (i = 0; i < 10; i++) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], 0); + + equalizerwin_eq_changed(); +} + +void +action_equ_load_preset_file(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + load_preset_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_load_preset_eqf(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + load_winamp_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_import_winamp_presets(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + import_winamp_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_save_preset(void) +{ + if (equalizerwin_save_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_save_window)); + return; + } + + equalizerwin_create_list_window(equalizer_presets, + Q_("Save preset"), + &equalizerwin_save_window, + GTK_SELECTION_SINGLE, + &equalizerwin_save_entry, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_save_ok), + G_CALLBACK(equalizerwin_save_select)); +} + +void +action_equ_save_auto_preset(void) +{ + gchar *name; + Playlist *playlist = aud_playlist_get_active(); + + if (equalizerwin_save_auto_window) + gtk_window_present(GTK_WINDOW(equalizerwin_save_auto_window)); + else + equalizerwin_create_list_window(equalizer_auto_presets, + Q_("Save auto-preset"), + &equalizerwin_save_auto_window, + GTK_SELECTION_SINGLE, + &equalizerwin_save_auto_entry, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_save_auto_ok), + G_CALLBACK(equalizerwin_save_auto_select)); + + name = aud_playlist_get_filename(playlist, aud_playlist_get_position(playlist)); + if (name) { + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), + g_basename(name)); + g_free(name); + } +} + +void +action_equ_save_default_preset(void) +{ + equalizer_presets = + equalizerwin_save_preset(equalizer_presets, Q_("Default"), "eq.preset"); +} + +void +action_equ_save_preset_file(void) +{ + GtkWidget *dialog; + gchar *file_uri; + gchar *songname; + Playlist *playlist = aud_playlist_get_active(); + + dialog = make_filebrowser(Q_("Save equalizer preset"), TRUE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + save_preset_file(file_uri); + g_free(file_uri); + } + + songname = aud_playlist_get_filename(playlist, aud_playlist_get_position(playlist)); + if (songname) { + gchar *eqname = g_strdup_printf("%s.%s", songname, + aud_cfg->eqpreset_extension); + g_free(songname); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), + eqname); + g_free(eqname); + } + + gtk_widget_destroy(dialog); +} + +void +action_equ_save_preset_eqf(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Save equalizer preset"), TRUE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + save_winamp_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_delete_preset(void) +{ + if (equalizerwin_delete_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_delete_window)); + return; + } + + equalizerwin_create_list_window(equalizer_presets, + Q_("Delete preset"), + &equalizerwin_delete_window, + GTK_SELECTION_EXTENDED, NULL, + GTK_STOCK_DELETE, + G_CALLBACK(equalizerwin_delete_delete), + NULL); +} + +void +action_equ_delete_auto_preset(void) +{ + if (equalizerwin_delete_auto_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_delete_auto_window)); + return; + } + + equalizerwin_create_list_window(equalizer_auto_presets, + Q_("Delete auto-preset"), + &equalizerwin_delete_auto_window, + GTK_SELECTION_EXTENDED, NULL, + GTK_STOCK_DELETE, + G_CALLBACK(equalizerwin_delete_auto_delete), + NULL); +} + +void +equalizer_activate(gboolean active) +{ + aud_cfg->equalizer_active = active; + UI_SKINNED_BUTTON(equalizerwin_on)->inside = active; + gtk_widget_queue_draw(equalizerwin_on); + + equalizerwin_eq_changed(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_equalizer.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,69 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_EQUALIZER_H +#define AUDACIOUS_UI_EQUALIZER_H + +#include <glib.h> +#include <gtk/gtk.h> +#include "skins_cfg.h" + +#define EQUALIZER_SCALED (config.scaled && config.eq_scaled_linked) +#define EQUALIZER_SCALE_FACTOR (EQUALIZER_SCALED ? config.scale_factor : 1) + +#define EQUALIZER_HEIGHT ((config.equalizer_shaded ? 14 : 116) * (EQUALIZER_SCALE_FACTOR)) +#define EQUALIZER_WIDTH (275 * EQUALIZER_SCALE_FACTOR) + +#define EQUALIZER_DEFAULT_POS_X 20 +#define EQUALIZER_DEFAULT_POS_Y 136 + +#define EQUALIZER_DEFAULT_DIR_PRESET "dir_default.preset" +#define EQUALIZER_DEFAULT_PRESET_EXT "preset" + +void equalizerwin_set_scaled(gboolean ds); +void equalizerwin_set_shade_menu_cb(gboolean shaded); +void draw_equalizer_window(gboolean force); +void equalizerwin_create(void); +void equalizerwin_show(gboolean show); +void equalizerwin_real_show(void); +void equalizerwin_real_hide(void); +void equalizerwin_load_auto_preset(const gchar * filename); +void equalizerwin_set_volume_slider(gint percent); +void equalizerwin_set_balance_slider(gint percent); +void equalizerwin_eq_changed(void); +void equalizerwin_set_preamp(gfloat preamp); +void equalizerwin_set_band(gint band, gfloat value); +gfloat equalizerwin_get_preamp(void); +gfloat equalizerwin_get_band(gint band); + +gboolean equalizerwin_has_focus(void); + +extern GtkWidget *equalizerwin; +extern GtkWidget *equalizerwin_graph; +extern gboolean equalizerwin_focus; + +void equalizer_activate(gboolean active); + +#endif /* AUDACIOUS_UI_EQUALIZER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_fileopener.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,489 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_fileopener.h" + +#include <glib/gi18n.h> +#include <string.h> +#include <gdk/gdkkeysyms.h> + +#include <audacious/input.h> +#include <audacious/main.h> +#include <audacious/playback.h> +#include <audacious/playlist.h> +#include <audacious/strings.h> +#include "ui_playlist.h" +#include "skins_cfg.h" + +static void +filebrowser_add_files(GtkFileChooser * browser, + GSList * files) +{ + GSList *cur; + gchar *ptr; + Playlist *playlist = aud_playlist_get_active(); + + for (cur = files; cur; cur = g_slist_next(cur)) { + gchar *filename = g_filename_to_uri((const gchar *) cur->data, NULL, NULL); + + if (aud_vfs_file_test(cur->data, G_FILE_TEST_IS_DIR)) { + aud_playlist_add_dir(playlist, filename ? filename : (const gchar *) cur->data); + } else { + aud_playlist_add(playlist, filename ? filename : (const gchar *) cur->data); + } + + g_free(filename); + } + + playlistwin_update_list(playlist); + + ptr = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(browser)); + + g_free(config.filesel_path); + config.filesel_path = ptr; +} + +static void +action_button_cb(GtkWidget *widget, gpointer data) +{ + GtkWidget *window = g_object_get_data(data, "window"); + GtkWidget *chooser = g_object_get_data(data, "chooser"); + GtkWidget *toggle = g_object_get_data(data, "toggle-button"); + gboolean play_button; + GSList *files; + config.close_dialog_open = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)); + + play_button = + GPOINTER_TO_INT(g_object_get_data(data, "play-button")); + + files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chooser)); + if (!files) return; + + if (play_button) + aud_playlist_clear(aud_playlist_get_active()); + + filebrowser_add_files(GTK_FILE_CHOOSER(chooser), files); + g_slist_foreach(files, (GFunc) g_free, NULL); + g_slist_free(files); + + if (play_button) + audacious_drct_initiate(); + + if (config.close_dialog_open) + gtk_widget_destroy(window); +} + + +static void +close_button_cb(GtkWidget *widget, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(data)); +} + +static gboolean +filebrowser_on_keypress(GtkWidget * browser, + GdkEventKey * event, + gpointer data) +{ + if (event->keyval == GDK_Escape) { + gtk_widget_destroy(browser); + return TRUE; + } + + return FALSE; +} + +static void +util_run_filebrowser_gtk2style(gboolean play_button, gboolean show) +{ + static GtkWidget *window = NULL; + GtkWidget *vbox, *hbox, *bbox; + GtkWidget *chooser; + GtkWidget *action_button, *close_button; + GtkWidget *toggle; + gchar *window_title, *toggle_text; + gpointer action_stock, storage; + + if(!show) { + if(window){ + gtk_widget_hide(window); + return; + } + else + return; + } + else { + if(window) { + gtk_window_present(GTK_WINDOW(window)); /* raise filebrowser */ + return; + } + } + + window_title = play_button ? _("Open Files") : _("Add Files"); + toggle_text = play_button ? + _("Close dialog on Open") : _("Close dialog on Add"); + action_stock = play_button ? GTK_STOCK_OPEN : GTK_STOCK_ADD; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), window_title); + gtk_window_set_default_size(GTK_WINDOW(window), 700, 450); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox); + + chooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), TRUE); + if (config.filesel_path) + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), + config.filesel_path); + gtk_box_pack_start(GTK_BOX(vbox), chooser, TRUE, TRUE, 3); + + hbox = gtk_hbox_new(TRUE, 0); + gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); + + toggle = gtk_check_button_new_with_label(toggle_text); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), + config.close_dialog_open ? TRUE : FALSE); + gtk_box_pack_start(GTK_BOX(hbox), toggle, TRUE, TRUE, 3); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(bbox), 6); + gtk_box_pack_end(GTK_BOX(hbox), bbox, TRUE, TRUE, 3); + + close_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + action_button = gtk_button_new_from_stock(action_stock); + gtk_container_add(GTK_CONTAINER(bbox), close_button); + gtk_container_add(GTK_CONTAINER(bbox), action_button); + + /* this storage object holds several other objects which are used in the + * callback functions + */ + storage = g_object_new(G_TYPE_OBJECT, NULL); + g_object_set_data(storage, "window", window); + g_object_set_data(storage, "chooser", chooser); + g_object_set_data(storage, "toggle-button", toggle); + g_object_set_data(storage, "play-button", GINT_TO_POINTER(play_button)); + + g_signal_connect(chooser, "file-activated", + G_CALLBACK(action_button_cb), storage); + g_signal_connect(action_button, "clicked", + G_CALLBACK(action_button_cb), storage); + g_signal_connect(close_button, "clicked", + G_CALLBACK(close_button_cb), window); + g_signal_connect(window, "destroy", + G_CALLBACK(gtk_widget_destroyed), &window); + + g_signal_connect(window, "key_press_event", + G_CALLBACK(filebrowser_on_keypress), + NULL); + + gtk_widget_show_all(window); +} + +/* + * Derived from Beep Media Player 0.9.6.1. + * Which is (C) 2003 - 2006 Milosz Derezynski &c + * + * Although I changed it quite a bit. -nenolod + */ +static void filebrowser_changed_classic(GtkFileSelection * filesel) +{ + GList *list; + GList *node; + char *filename = (char *) + gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel)); + GtkListStore *store; + GtkTreeIter iter; + +#if 0 + if ((list = input_scan_dir(filename)) != NULL) + { + /* + * We enter a directory that has been "hijacked" by an + * input-plugin. This is used by the CDDA plugin + */ + store = + GTK_LIST_STORE(gtk_tree_view_get_model + (GTK_TREE_VIEW(filesel->file_list))); + gtk_list_store_clear(store); + + node = list; + while (node) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, node->data, -1); + g_free(node->data); + node = g_list_next(node); + } + + g_list_free(list); + } +#endif +} + +static void filebrowser_entry_changed_classic(GtkEditable * entry, gpointer data) +{ + filebrowser_changed_classic(GTK_FILE_SELECTION(data)); +} + + +static gboolean +util_filebrowser_is_dir_classic(GtkFileSelection * filesel) +{ + char *text; + struct stat buf; + gboolean retv = FALSE; + + text = g_strdup(gtk_file_selection_get_filename(filesel)); + + if (stat(text, &buf) == 0 && S_ISDIR(buf.st_mode)) { + /* Selected directory */ + int len = strlen(text); + if (len > 3 && !strcmp(text + len - 4, "/../")) { + if (len == 4) + /* At the root already */ + *(text + len - 3) = '\0'; + else { + char *ptr; + *(text + len - 4) = '\0'; + ptr = strrchr(text, '/'); + *(ptr + 1) = '\0'; + } + } else if (len > 2 && !strcmp(text + len - 3, "/./")) + *(text + len - 2) = '\0'; + gtk_file_selection_set_filename(filesel, text); + retv = TRUE; + } + g_free(text); + return retv; +} + +static void filebrowser_add_files_classic(gchar ** files, + GtkFileSelection * filesel) +{ + int ctr = 0; + char *ptr; + Playlist *playlist = aud_playlist_get_active(); + + while (files[ctr] != NULL) { + gchar *filename = g_filename_to_uri((const gchar *) files[ctr++], NULL, NULL); + aud_playlist_add(playlist, filename); + g_free(filename); + } + playlistwin_update_list(playlist); + + gtk_label_get(GTK_LABEL(GTK_BIN(filesel->history_pulldown)->child), + &ptr); + + /* This will give an extra slash if the current dir is the root. */ + config.filesel_path = g_strconcat(ptr, "/", NULL); +} + +static void filebrowser_ok_classic(GtkWidget * w, GtkWidget * filesel) +{ + gchar **files; + + if (util_filebrowser_is_dir_classic(GTK_FILE_SELECTION(filesel))) + return; + files = gtk_file_selection_get_selections(GTK_FILE_SELECTION(filesel)); + filebrowser_add_files_classic(files, GTK_FILE_SELECTION(filesel)); + gtk_widget_destroy(filesel); +} + +static void filebrowser_play_classic(GtkWidget * w, GtkWidget * filesel) +{ + gchar **files; + + if (util_filebrowser_is_dir_classic + (GTK_FILE_SELECTION(GTK_FILE_SELECTION(filesel)))) + return; + aud_playlist_clear(aud_playlist_get_active()); + files = gtk_file_selection_get_selections(GTK_FILE_SELECTION(filesel)); + filebrowser_add_files_classic(files, GTK_FILE_SELECTION(filesel)); + gtk_widget_destroy(filesel); + + audacious_drct_initiate(); +} + +static void filebrowser_add_selected_files_classic(GtkWidget * w, gpointer data) +{ + gchar **files; + + GtkFileSelection *filesel = GTK_FILE_SELECTION(data); + files = gtk_file_selection_get_selections(filesel); + + filebrowser_add_files_classic(files, filesel); + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection + (GTK_TREE_VIEW(filesel->file_list))); + + gtk_entry_set_text(GTK_ENTRY(filesel->selection_entry), ""); +} + +static void filebrowser_add_all_files_classic(GtkWidget * w, gpointer data) +{ + gchar **files; + GtkFileSelection *filesel; + + filesel = data; + gtk_tree_selection_select_all(gtk_tree_view_get_selection + (GTK_TREE_VIEW(filesel->file_list))); + files = gtk_file_selection_get_selections(filesel); + filebrowser_add_files_classic(files, filesel); + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection + (GTK_TREE_VIEW(filesel->file_list))); + gtk_entry_set_text(GTK_ENTRY(filesel->selection_entry), ""); +} + +static void +util_run_filebrowser_classic(gboolean play_button, gboolean show) +{ + static GtkWidget *dialog; + GtkWidget *button_add_selected, *button_add_all, *button_close, + *button_add; + char *title; + + if (!show) { + if(dialog) { + gtk_widget_hide(dialog); + return; + } + else + return; + } + else { + if (dialog) { + gtk_window_present(GTK_WINDOW(dialog)); + return; + } + } + + if (play_button) + title = _("Play files"); + else + title = _("Load files"); + + dialog = gtk_file_selection_new(title); + + gtk_file_selection_set_select_multiple + (GTK_FILE_SELECTION(dialog), TRUE); + + if (config.filesel_path) + gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog), + config.filesel_path); + + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(dialog)); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_widget_hide(GTK_FILE_SELECTION(dialog)->ok_button); + gtk_widget_destroy(GTK_FILE_SELECTION(dialog)->cancel_button); + + /* + * The mnemonics are quite unorthodox, but that should guarantee they're unique in any locale + * plus kinda easy to use + */ + button_add_selected = + gtk_dialog_add_button(GTK_DIALOG(dialog), "Add selected", + GTK_RESPONSE_NONE); + gtk_button_set_use_underline(GTK_BUTTON(button_add_selected), TRUE); + g_signal_connect(G_OBJECT(button_add_selected), "clicked", + G_CALLBACK(filebrowser_add_selected_files_classic), dialog); + + button_add_all = + gtk_dialog_add_button(GTK_DIALOG(dialog), "Add all", + GTK_RESPONSE_NONE); + gtk_button_set_use_underline(GTK_BUTTON(button_add_all), TRUE); + g_signal_connect(G_OBJECT(button_add_all), "clicked", + G_CALLBACK(filebrowser_add_all_files_classic), dialog); + + if (play_button) { + button_add = + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_MEDIA_PLAY, + GTK_RESPONSE_NONE); + gtk_button_set_use_stock(GTK_BUTTON(button_add), TRUE); + g_signal_connect(G_OBJECT(button_add), "clicked", + G_CALLBACK(filebrowser_play_classic), dialog); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dialog)->ok_button), + "clicked", G_CALLBACK(filebrowser_play_classic), dialog); + } else { + button_add = + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_ADD, + GTK_RESPONSE_NONE); + gtk_button_set_use_stock(GTK_BUTTON(button_add), TRUE); + g_signal_connect(G_OBJECT(button_add), "clicked", + G_CALLBACK(filebrowser_ok_classic), dialog); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dialog)->ok_button), + "clicked", G_CALLBACK(filebrowser_ok_classic), dialog); + } + + button_close = + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CLOSE, + GTK_RESPONSE_NONE); + gtk_button_set_use_stock(GTK_BUTTON(button_close), TRUE); + g_signal_connect_swapped(G_OBJECT(button_close), "clicked", + G_CALLBACK(gtk_widget_destroy), + G_OBJECT(dialog)); + + gtk_widget_set_size_request(dialog, 600, 450); + gtk_widget_realize(dialog); + + g_signal_connect(G_OBJECT + (GTK_FILE_SELECTION(dialog)->history_pulldown), + "changed", G_CALLBACK(filebrowser_entry_changed_classic), + dialog); + + g_signal_connect(G_OBJECT(dialog), "destroy", + G_CALLBACK(gtk_widget_destroyed), &dialog); + + filebrowser_changed_classic(GTK_FILE_SELECTION(dialog)); + + gtk_widget_show(dialog); +} + +/* + * util_run_filebrowser(gboolean play_button) + * + * Inputs: + * - whether or not a play button should be used + * + * Outputs: + * - none + * + * Side Effects: + * - either a GTK1 or a GTK2 fileselector is launched + */ +void +run_filebrowser(gboolean play_button) +{ + if (!config.use_xmms_style_fileselector) + util_run_filebrowser_gtk2style(play_button, TRUE); + else + util_run_filebrowser_classic(play_button, TRUE); +} + +void +hide_filebrowser(void) +{ + if (!config.use_xmms_style_fileselector) + util_run_filebrowser_gtk2style(FALSE, FALSE); + else + util_run_filebrowser_classic(FALSE, FALSE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_fileopener.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,31 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_FILEOPENER_H +#define AUDACIOUS_UI_FILEOPENER_H + +#include <gtk/gtk.h> + +#define NO_PLAY_BUTTON FALSE +#define PLAY_BUTTON TRUE + +void run_filebrowser(gboolean clear_pl_on_ok); +void hide_filebrowser(void); + +#endif /* AUDACIOUS_UI_FILEOPENER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_hints.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,59 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_hints.h" + +#include <glib.h> +#include <gtk/gtk.h> + +#include "ui_equalizer.h" +#include "ui_main.h" +#include "ui_playlist.h" + +#include "platform/smartinclude.h" + +void +hint_set_always(gboolean always) +{ + gtk_window_set_keep_above(GTK_WINDOW(mainwin), always); + gtk_window_set_keep_above(GTK_WINDOW(equalizerwin), always); + gtk_window_set_keep_above(GTK_WINDOW(playlistwin), always); +} + +void +hint_set_sticky(gboolean sticky) +{ + if (sticky) { + gtk_window_stick(GTK_WINDOW(mainwin)); + gtk_window_stick(GTK_WINDOW(equalizerwin)); + gtk_window_stick(GTK_WINDOW(playlistwin)); + } + else { + gtk_window_unstick(GTK_WINDOW(mainwin)); + gtk_window_unstick(GTK_WINDOW(equalizerwin)); + gtk_window_unstick(GTK_WINDOW(playlistwin)); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_hints.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,35 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_HINTS_H +#define AUDACIOUS_UI_HINTS_H + +#include <glib.h> +#include <gtk/gtk.h> + +void hint_set_always(gboolean always); +void hint_set_sticky(gboolean sticky); + +#endif /* AUDACIOUS_UI_HINTS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_main.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,2909 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2006 Audacious development team. + * + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gprintf.h> +#include <gtk/gtk.h> +#include <gtk/gtkmessagedialog.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +/* GDK including */ +#include "platform/smartinclude.h" + +#if defined(USE_REGEX_ONIGURUMA) +#include <onigposix.h> +#elif defined(USE_REGEX_PCRE) +#include <pcreposix.h> +#else +#include <regex.h> +#endif + +#include "ui_main.h" +#include "ui_dock.h" +#include "icons-stock.h" +#include "actions-mainwin.h" +#include "ui_manager.h" +#include "ui_equalizer.h" +#include "ui_playlist.h" +#include "ui_hints.h" +#include "dnd.h" +#if 0 +#include "configdb.h" +#include "input.h" +#include "main.h" +#include "playback.h" +#include "playlist.h" +#include "pluginenum.h" +#include "strings.h" +#include "ui_credits.h" +#include "ui_dock.h" +#include "ui_fileinfo.h" +#include "ui_jumptotrack.h" +#include "ui_main_evlisteners.h" +#include "ui_preferences.h" +#include "ui_skinselector.h" +#include "ui_urlopener.h" +#include "util.h" +#include "visualization.h" +#endif +#include "ui_fileopener.h" +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_textbox.h" +#include "ui_skinned_number.h" +#include "ui_skinned_horizontal_slider.h" +#include "ui_skinned_menurow.h" +#include "ui_skinned_playstatus.h" +#include "ui_skinned_monostereo.h" +#include "ui_skinned_playlist.h" +#include <audacious/plugin.h> +#include "skins_cfg.h" + +static GTimeVal cb_time; +static const int TRISTATE_THRESHOLD = 200; + +enum { + MAINWIN_SEEK_REV = -1, + MAINWIN_SEEK_NIL, + MAINWIN_SEEK_FWD +}; + +GtkWidget *mainwin = NULL; + +static gint balance; + +static GtkWidget *mainwin_jtt = NULL; + +static gint seek_state = MAINWIN_SEEK_NIL; +static gint seek_initial_pos = 0; + +static GtkWidget *mainwin_menubtn; +static GtkWidget *mainwin_minimize, *mainwin_shade, *mainwin_close; + +static GtkWidget *mainwin_rew, *mainwin_fwd; +static GtkWidget *mainwin_eject; +static GtkWidget *mainwin_play, *mainwin_pause, *mainwin_stop; + +static GtkWidget *mainwin_shuffle, *mainwin_repeat; +GtkWidget *mainwin_eq, *mainwin_pl; + +GtkWidget *mainwin_info; +GtkWidget *mainwin_stime_min, *mainwin_stime_sec; + +static GtkWidget *mainwin_rate_text, *mainwin_freq_text, *mainwin_othertext; + +GtkWidget *mainwin_playstatus; + +GtkWidget *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; +GtkWidget *mainwin_10sec_num, *mainwin_sec_num; + +GtkWidget *mainwin_vis; +GtkWidget *mainwin_svis; + +GtkWidget *mainwin_sposition = NULL; + +static GtkWidget *mainwin_menurow; +static GtkWidget *mainwin_volume, *mainwin_balance; +GtkWidget *mainwin_position; + +static GtkWidget *mainwin_monostereo; +static GtkWidget *mainwin_srew, *mainwin_splay, *mainwin_spause; +static GtkWidget *mainwin_sstop, *mainwin_sfwd, *mainwin_seject, *mainwin_about; + +static gint mainwin_timeout_id; + +static gboolean mainwin_info_text_locked = FALSE; +static guint mainwin_volume_release_timeout = 0; + +static int ab_position_a = -1; +static int ab_position_b = -1; + +static void mainwin_refresh_visible(void); +static gint mainwin_idle_func(gpointer data); + +static void set_timer_mode_menu_cb(TimerMode mode); +static void set_timer_mode(TimerMode mode); +static void change_timer_mode(void); + +static void mainwin_position_motion_cb(GtkWidget *widget, gint pos); +static void mainwin_position_release_cb(GtkWidget *widget, gint pos); + +static void set_scaled(gboolean scaled); +static void mainwin_eq_pushed(gboolean toggled); +static void mainwin_pl_pushed(gboolean toggled); + +static void +mainwin_set_title_scroll(gboolean scroll) +{ + config.autoscroll = scroll; + ui_skinned_textbox_set_scroll(mainwin_info, config.autoscroll); +} + + +void +mainwin_set_always_on_top(gboolean always) +{ + GtkAction *action = gtk_action_group_get_action(toggleaction_group_others, + "view always on top"); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , always ); +} + +static void +mainwin_set_shade(gboolean shaded) +{ + GtkAction *action = gtk_action_group_get_action(toggleaction_group_others, + "roll up player"); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); +} + +static void +mainwin_set_shade_menu_cb(gboolean shaded) +{ + config.player_shaded = shaded; + + if (shaded) { + dock_shade(get_dock_window_list(), GTK_WINDOW(mainwin), + MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR); + } else { + gint height = !aud_active_skin->properties.mainwin_height ? MAINWIN_HEIGHT : + aud_active_skin->properties.mainwin_height; + + dock_shade(get_dock_window_list(), GTK_WINDOW(mainwin), height * MAINWIN_SCALE_FACTOR); + } + + mainwin_refresh_hints(); + ui_skinned_set_push_button_data(mainwin_shade, 0, config.player_shaded ? 27 : 18, 9, config.player_shaded ? 27 : 18); + gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + config.player_shaded), 0, 0); +} + +static void +mainwin_vis_set_refresh(RefreshRate rate) +{ + config.vis_refresh = rate; +} + +static void +mainwin_vis_set_afalloff(FalloffSpeed speed) +{ + config.analyzer_falloff = speed; +} + +static void +mainwin_vis_set_pfalloff(FalloffSpeed speed) +{ + config.peaks_falloff = speed; +} + +static void +mainwin_vis_set_analyzer_mode(AnalyzerMode mode) +{ + config.analyzer_mode = mode; +} + +static void +mainwin_vis_set_analyzer_type(AnalyzerType mode) +{ + config.analyzer_type = mode; +} + +void +mainwin_vis_set_type(VisType mode) +{ + GtkAction *action; + + switch ( mode ) + { + case VIS_ANALYZER: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode analyzer"); + break; + case VIS_SCOPE: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode scope"); + break; + case VIS_VOICEPRINT: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode voiceprint"); + break; + case VIS_OFF: + default: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode off"); + break; + } + + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE ); +} + +static void +mainwin_vis_set_type_menu_cb(VisType mode) +{ + config.vis_type = mode; + + if (mode == VIS_OFF) { + if (config.player_shaded) { + ui_svis_set_visible(mainwin_svis, FALSE); + ui_vis_set_visible(mainwin_vis, TRUE); + } else { + ui_svis_set_visible(mainwin_svis, TRUE); + ui_vis_set_visible(mainwin_vis, FALSE); + } + } + if (mode == VIS_ANALYZER || mode == VIS_SCOPE || mode == VIS_VOICEPRINT) { + if (config.player_shaded) { + ui_svis_clear_data(mainwin_svis); + ui_svis_set_visible(mainwin_svis, TRUE); + ui_vis_clear_data(mainwin_vis); + ui_vis_set_visible(mainwin_vis, FALSE); + } else { + ui_svis_clear_data(mainwin_svis); + ui_svis_set_visible(mainwin_svis, FALSE); + ui_vis_clear_data(mainwin_vis); + ui_vis_set_visible(mainwin_vis, TRUE); + } + } +} + +static void +mainwin_menubtn_cb(void) +{ + gint x, y; + gtk_window_get_position(GTK_WINDOW(mainwin), &x, &y); + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), + x + 6 * MAINWIN_SCALE_FACTOR , + y + MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR, + 1, GDK_CURRENT_TIME); +} + +void +mainwin_minimize_cb(void) +{ + if (!mainwin) + return; + + gtk_window_iconify(GTK_WINDOW(mainwin)); +} + +static void +mainwin_shade_toggle(void) +{ + mainwin_set_shade(!config.player_shaded); +} + +void +mainwin_quit_cb(void) +{ + if (mainwin_timeout_id) + g_source_remove(mainwin_timeout_id); + + audacious_drct_quit(); +} + +gboolean +mainwin_vis_cb(GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1) { + config.vis_type++; + + if (config.vis_type > VIS_OFF) + config.vis_type = VIS_ANALYZER; + + mainwin_vis_set_type(config.vis_type); + } else if (event->button == 3) { + ui_manager_popup_menu_show(GTK_MENU(mainwin_visualization_menu), + event->x_root, event->y_root, 3, + event->time); + } + return TRUE; +} + +static void +mainwin_destroy(GtkWidget * widget, gpointer data) +{ +/* we should detect whether plugin got unloaded and when user indeed + wants to close audacious */ +#if 0 + mainwin_quit_cb(); +#endif +} + +static gchar *mainwin_tb_old_text = NULL; + +void +mainwin_lock_info_text(const gchar * text) +{ + if (mainwin_info_text_locked != TRUE) + mainwin_tb_old_text = g_strdup(aud_active_skin->properties.mainwin_othertext_is_status ? + UI_SKINNED_TEXTBOX(mainwin_othertext)->text : UI_SKINNED_TEXTBOX(mainwin_info)->text); + + mainwin_info_text_locked = TRUE; + if (aud_active_skin->properties.mainwin_othertext_is_status) + ui_skinned_textbox_set_text(mainwin_othertext, text); + else + ui_skinned_textbox_set_text(mainwin_info, text); +} + +void +mainwin_release_info_text(void) +{ + mainwin_info_text_locked = FALSE; + + if (mainwin_tb_old_text != NULL) + { + if (aud_active_skin->properties.mainwin_othertext_is_status) + ui_skinned_textbox_set_text(mainwin_othertext, mainwin_tb_old_text); + else + ui_skinned_textbox_set_text(mainwin_info, mainwin_tb_old_text); + g_free(mainwin_tb_old_text); + mainwin_tb_old_text = NULL; + } +} + + +static gchar * +make_mainwin_title(const gchar * title) +{ + if (title) + return g_strdup_printf(_("%s - Audacious"), title); + else + return g_strdup(_("Audacious")); +} + +void +mainwin_set_song_title(const gchar * title) +{ + gchar *mainwin_title_text = make_mainwin_title(title); + gtk_window_set_title(GTK_WINDOW(mainwin), mainwin_title_text); + g_free(mainwin_title_text); +} + +static void +mainwin_refresh_visible(void) +{ + if (!aud_active_skin || !config.player_visible) + return; + + gtk_widget_show_all(mainwin); + + if (!aud_active_skin->properties.mainwin_text_visible) + gtk_widget_hide(mainwin_info); + + if (!aud_active_skin->properties.mainwin_vis_visible) + gtk_widget_hide(mainwin_vis); + + if (!aud_active_skin->properties.mainwin_menurow_visible) + gtk_widget_hide(mainwin_menurow); + + if (aud_active_skin->properties.mainwin_othertext) { + gtk_widget_hide(mainwin_rate_text); + gtk_widget_hide(mainwin_freq_text); + gtk_widget_hide(mainwin_monostereo); + + if (!aud_active_skin->properties.mainwin_othertext_visible) + gtk_widget_hide(mainwin_othertext); + } else { + gtk_widget_hide(mainwin_othertext); + } + + if (!aud_active_skin->properties.mainwin_vis_visible) + gtk_widget_hide(mainwin_vis); + + if (!audacious_drct_get_playing()) { + gtk_widget_hide(mainwin_minus_num); + gtk_widget_hide(mainwin_10min_num); + gtk_widget_hide(mainwin_min_num); + gtk_widget_hide(mainwin_10sec_num); + gtk_widget_hide(mainwin_sec_num); + + gtk_widget_hide(mainwin_stime_min); + gtk_widget_hide(mainwin_stime_sec); + + gtk_widget_hide(mainwin_position); + gtk_widget_hide(mainwin_sposition); + } + + if (config.player_shaded) { + ui_svis_clear_data(mainwin_svis); + if (config.vis_type != VIS_OFF) + ui_svis_set_visible(mainwin_svis, TRUE); + else + ui_svis_set_visible(mainwin_svis, FALSE); + + ui_skinned_textbox_set_scroll(mainwin_info, FALSE); + if (!audacious_drct_get_playing()) { + gtk_widget_hide(mainwin_sposition); + gtk_widget_hide(mainwin_stime_min); + gtk_widget_hide(mainwin_stime_sec); + } + } else { + gtk_widget_hide(mainwin_srew); + gtk_widget_hide(mainwin_splay); + gtk_widget_hide(mainwin_spause); + gtk_widget_hide(mainwin_sstop); + gtk_widget_hide(mainwin_sfwd); + gtk_widget_hide(mainwin_seject); + gtk_widget_hide(mainwin_stime_min); + gtk_widget_hide(mainwin_stime_sec); + gtk_widget_hide(mainwin_svis); + gtk_widget_hide(mainwin_sposition); + ui_vis_clear_data(mainwin_vis); + if (config.vis_type != VIS_OFF) + ui_vis_set_visible(mainwin_vis, TRUE); + else + ui_vis_set_visible(mainwin_vis, FALSE); + + ui_skinned_textbox_set_scroll(mainwin_info, config.autoscroll); + } +} + +void +mainwin_refresh_hints(void) +{ + /* positioning and size attributes */ + if (aud_active_skin->properties.mainwin_vis_x && aud_active_skin->properties.mainwin_vis_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_vis), aud_active_skin->properties.mainwin_vis_x, + aud_active_skin->properties.mainwin_vis_y); + + if (aud_active_skin->properties.mainwin_vis_width) + gtk_widget_set_size_request(mainwin_vis, aud_active_skin->properties.mainwin_vis_width * MAINWIN_SCALE_FACTOR, + UI_VIS(mainwin_vis)->height* MAINWIN_SCALE_FACTOR); + + if (aud_active_skin->properties.mainwin_text_x && aud_active_skin->properties.mainwin_text_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_info), aud_active_skin->properties.mainwin_text_x, + aud_active_skin->properties.mainwin_text_y); + + if (aud_active_skin->properties.mainwin_text_width) { + UI_SKINNED_TEXTBOX(mainwin_info)->width = aud_active_skin->properties.mainwin_text_width; + gtk_widget_set_size_request(mainwin_info, aud_active_skin->properties.mainwin_text_width * MAINWIN_SCALE_FACTOR, + UI_SKINNED_TEXTBOX(mainwin_info)->height * MAINWIN_SCALE_FACTOR ); + } + + if (aud_active_skin->properties.mainwin_infobar_x && aud_active_skin->properties.mainwin_infobar_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_othertext), aud_active_skin->properties.mainwin_infobar_x, + aud_active_skin->properties.mainwin_infobar_y); + + if (aud_active_skin->properties.mainwin_number_0_x && aud_active_skin->properties.mainwin_number_0_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_minus_num), aud_active_skin->properties.mainwin_number_0_x, + aud_active_skin->properties.mainwin_number_0_y); + + if (aud_active_skin->properties.mainwin_number_1_x && aud_active_skin->properties.mainwin_number_1_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_10min_num), aud_active_skin->properties.mainwin_number_1_x, + aud_active_skin->properties.mainwin_number_1_y); + + if (aud_active_skin->properties.mainwin_number_2_x && aud_active_skin->properties.mainwin_number_2_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_min_num), aud_active_skin->properties.mainwin_number_2_x, + aud_active_skin->properties.mainwin_number_2_y); + + if (aud_active_skin->properties.mainwin_number_3_x && aud_active_skin->properties.mainwin_number_3_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_10sec_num), aud_active_skin->properties.mainwin_number_3_x, + aud_active_skin->properties.mainwin_number_3_y); + + if (aud_active_skin->properties.mainwin_number_4_x && aud_active_skin->properties.mainwin_number_4_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_sec_num), aud_active_skin->properties.mainwin_number_4_x, + aud_active_skin->properties.mainwin_number_4_y); + + if (aud_active_skin->properties.mainwin_playstatus_x && aud_active_skin->properties.mainwin_playstatus_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), mainwin_playstatus, aud_active_skin->properties.mainwin_playstatus_x, + aud_active_skin->properties.mainwin_playstatus_y); + + if (aud_active_skin->properties.mainwin_volume_x && aud_active_skin->properties.mainwin_volume_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_volume), aud_active_skin->properties.mainwin_volume_x, + aud_active_skin->properties.mainwin_volume_y); + + if (aud_active_skin->properties.mainwin_balance_x && aud_active_skin->properties.mainwin_balance_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_balance), aud_active_skin->properties.mainwin_balance_x, + aud_active_skin->properties.mainwin_balance_y); + + if (aud_active_skin->properties.mainwin_position_x && aud_active_skin->properties.mainwin_position_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_position), aud_active_skin->properties.mainwin_position_x, + aud_active_skin->properties.mainwin_position_y); + + if (aud_active_skin->properties.mainwin_previous_x && aud_active_skin->properties.mainwin_previous_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), mainwin_rew, aud_active_skin->properties.mainwin_previous_x, + aud_active_skin->properties.mainwin_previous_y); + + if (aud_active_skin->properties.mainwin_play_x && aud_active_skin->properties.mainwin_play_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_play), aud_active_skin->properties.mainwin_play_x, + aud_active_skin->properties.mainwin_play_y); + + if (aud_active_skin->properties.mainwin_pause_x && aud_active_skin->properties.mainwin_pause_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_pause), aud_active_skin->properties.mainwin_pause_x, + aud_active_skin->properties.mainwin_pause_y); + + if (aud_active_skin->properties.mainwin_stop_x && aud_active_skin->properties.mainwin_stop_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_stop), aud_active_skin->properties.mainwin_stop_x, + aud_active_skin->properties.mainwin_stop_y); + + if (aud_active_skin->properties.mainwin_next_x && aud_active_skin->properties.mainwin_next_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_fwd), aud_active_skin->properties.mainwin_next_x, + aud_active_skin->properties.mainwin_next_y); + + if (aud_active_skin->properties.mainwin_eject_x && aud_active_skin->properties.mainwin_eject_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_eject), aud_active_skin->properties.mainwin_eject_x, + aud_active_skin->properties.mainwin_eject_y); + + if (aud_active_skin->properties.mainwin_eqbutton_x && aud_active_skin->properties.mainwin_eqbutton_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_eq), aud_active_skin->properties.mainwin_eqbutton_x, + aud_active_skin->properties.mainwin_eqbutton_y); + + if (aud_active_skin->properties.mainwin_plbutton_x && aud_active_skin->properties.mainwin_plbutton_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_pl), aud_active_skin->properties.mainwin_plbutton_x, + aud_active_skin->properties.mainwin_plbutton_y); + + if (aud_active_skin->properties.mainwin_shuffle_x && aud_active_skin->properties.mainwin_shuffle_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_shuffle), aud_active_skin->properties.mainwin_shuffle_x, + aud_active_skin->properties.mainwin_shuffle_y); + + if (aud_active_skin->properties.mainwin_repeat_x && aud_active_skin->properties.mainwin_repeat_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_repeat), aud_active_skin->properties.mainwin_repeat_x, + aud_active_skin->properties.mainwin_repeat_y); + + if (aud_active_skin->properties.mainwin_about_x && aud_active_skin->properties.mainwin_about_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_about), aud_active_skin->properties.mainwin_about_x, + aud_active_skin->properties.mainwin_about_y); + + if (aud_active_skin->properties.mainwin_minimize_x && aud_active_skin->properties.mainwin_minimize_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_minimize), config.player_shaded ? 244 : aud_active_skin->properties.mainwin_minimize_x, + config.player_shaded ? 3 : aud_active_skin->properties.mainwin_minimize_y); + + if (aud_active_skin->properties.mainwin_shade_x && aud_active_skin->properties.mainwin_shade_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_shade), config.player_shaded ? 254 : aud_active_skin->properties.mainwin_shade_x, + config.player_shaded ? 3 : aud_active_skin->properties.mainwin_shade_y); + + if (aud_active_skin->properties.mainwin_close_x && aud_active_skin->properties.mainwin_close_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_close), config.player_shaded ? 264 : aud_active_skin->properties.mainwin_close_x, + config.player_shaded ? 3 : aud_active_skin->properties.mainwin_close_y); + + mainwin_refresh_visible(); + + /* window size, mainwinWidth && mainwinHeight properties */ + if (aud_active_skin->properties.mainwin_height && aud_active_skin->properties.mainwin_width) + { + dock_window_resize(GTK_WINDOW(mainwin), config.player_shaded ? MAINWIN_SHADED_WIDTH * MAINWIN_SCALE_FACTOR : aud_active_skin->properties.mainwin_width * MAINWIN_SCALE_FACTOR, + config.player_shaded ? MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR : aud_active_skin->properties.mainwin_height * MAINWIN_SCALE_FACTOR, + aud_active_skin->properties.mainwin_width * MAINWIN_SCALE_FACTOR, + aud_active_skin->properties.mainwin_height * MAINWIN_SCALE_FACTOR); + + gdk_flush(); + } +} + +void +mainwin_set_song_info(gint bitrate, + gint frequency, + gint n_channels) +{ + gchar *text; + gchar *title; + Playlist *playlist = aud_playlist_get_active(); + + GDK_THREADS_ENTER(); + if (bitrate != -1) { + bitrate /= 1000; + + if (bitrate < 1000) { + /* Show bitrate in 1000s */ + text = g_strdup_printf("%3d", bitrate); + } + else { + /* Show bitrate in 100,000s */ + text = g_strdup_printf("%2dH", bitrate / 100); + } + ui_skinned_textbox_set_text(mainwin_rate_text, text); + g_free(text); + } + else + ui_skinned_textbox_set_text(mainwin_rate_text, _("VBR")); + + /* Show sampling frequency in kHz */ + text = g_strdup_printf("%2d", frequency / 1000); + ui_skinned_textbox_set_text(mainwin_freq_text, text); + g_free(text); + + ui_skinned_monostereo_set_num_channels(mainwin_monostereo, n_channels); + + if (!audacious_drct_get_paused() && mainwin_playstatus != NULL) + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); + + if (aud_active_skin && aud_active_skin->properties.mainwin_othertext) + { + if (bitrate != -1) + text = g_strdup_printf("%d kbps, %0.1f kHz, %s", + bitrate, + (gfloat) frequency / 1000, + (n_channels > 1) ? _("stereo") : _("mono")); + else + text = g_strdup_printf("VBR, %0.1f kHz, %s", + (gfloat) frequency / 1000, + (n_channels > 1) ? _("stereo") : _("mono")); + + ui_skinned_textbox_set_text(mainwin_othertext, text); + g_free(text); + } + + title = aud_playlist_get_info_text(playlist); + mainwin_set_song_title(title); + g_free(title); + GDK_THREADS_LEAVE(); +} + +void +mainwin_clear_song_info(void) +{ + if (!mainwin) + return; + + /* clear title */ + mainwin_set_song_title(NULL); + +#if 0 + /* clear sampling parameters */ + playback_set_sample_params(0, 0, 0); +#endif + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_position)->pressed = FALSE; + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->pressed = FALSE; + + /* clear sampling parameter displays */ + ui_skinned_textbox_set_text(mainwin_rate_text, " "); + ui_skinned_textbox_set_text(mainwin_freq_text, " "); + ui_skinned_monostereo_set_num_channels(mainwin_monostereo, 0); + + if (mainwin_playstatus != NULL) + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_STOP); + + mainwin_refresh_visible(); + + playlistwin_hide_timer(); + + ui_vis_clear_data(mainwin_vis); + ui_svis_clear_data(mainwin_svis); +} + +void +mainwin_disable_seekbar(void) +{ + if (!mainwin) + return; + + gtk_widget_hide(mainwin_position); + gtk_widget_hide(mainwin_sposition); +} + +static gboolean +mainwin_mouse_button_release(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + if (dock_is_moving(GTK_WINDOW(mainwin))) { + dock_move_release(GTK_WINDOW(mainwin)); + } + + return FALSE; +} + +void +mainwin_scrolled(GtkWidget *widget, GdkEventScroll *event, + gpointer callback_data) +{ + Playlist *playlist = aud_playlist_get_active(); + + switch (event->direction) { + case GDK_SCROLL_UP: + mainwin_set_volume_diff(config.mouse_change); + break; + case GDK_SCROLL_DOWN: + mainwin_set_volume_diff(-config.mouse_change); + break; + case GDK_SCROLL_LEFT: + if (aud_playlist_get_current_length(playlist) != -1) + audacious_drct_seek(CLAMP(audacious_drct_get_time() - 1000, + 0, aud_playlist_get_current_length(playlist)) / 1000); + break; + case GDK_SCROLL_RIGHT: + if (aud_playlist_get_current_length(playlist) != -1) + audacious_drct_seek(CLAMP(audacious_drct_get_time() + 1000, + 0, aud_playlist_get_current_length(playlist)) / 1000); + break; + } +} + +static gboolean +mainwin_widget_contained(GdkEventButton *event, int x, int y, int w, int h) +{ + if ((event->x > x && event->y > y) && + (event->x < x+w && event->y < y+h)) + return TRUE; + + return FALSE; +} + +static gboolean +mainwin_mouse_button_press(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + if (config.scaled) { + /* + * A hack to make scaling transparent to callbacks. + * We should make a copy of this data instead of + * tampering with the data we get from gtk+ + */ + event->x /= config.scale_factor; + event->y /= config.scale_factor; + } + + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && event->y < 14) { + mainwin_set_shade(!config.player_shaded); + if (dock_is_moving(GTK_WINDOW(mainwin))) + dock_move_release(GTK_WINDOW(mainwin)); + return TRUE; + } + + if (event->button == 3) { + /* Pop up playback menu if right clicked over playback-control widgets, + * otherwise popup general menu + */ + if (mainwin_widget_contained(event, aud_active_skin->properties.mainwin_position_x, + aud_active_skin->properties.mainwin_position_y, 248, 10) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_previous_x, + aud_active_skin->properties.mainwin_previous_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_play_x, + aud_active_skin->properties.mainwin_play_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_pause_x, + aud_active_skin->properties.mainwin_pause_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_stop_x, + aud_active_skin->properties.mainwin_stop_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_next_x, + aud_active_skin->properties.mainwin_next_y, 23, 18)) + { + + ui_manager_popup_menu_show(GTK_MENU(mainwin_playback_menu), + event->x_root, + event->y_root, 3, event->time); + + } else { + /* + * Pop up the main menu a few pixels down. + * This will avoid that anything is selected + * if one right-clicks to focus the window + * without raising it. + * + ***MD I think the above is stupid, people don't expect this + * + */ + + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), + event->x_root, + event->y_root, 3, event->time); + + } + return TRUE; + } + + return FALSE; +} + +static gboolean +mainwin_keypress(GtkWidget * grab_widget, + GdkEventKey * event, + gpointer data) +{ + Playlist *playlist = aud_playlist_get_active(); + + switch (event->keyval) { + + case GDK_Up: + case GDK_KP_Up: + case GDK_KP_8: + mainwin_set_volume_diff(2); + break; + case GDK_Down: + case GDK_KP_Down: + case GDK_KP_2: + mainwin_set_volume_diff(-2); + break; + case GDK_Left: + case GDK_KP_Left: + case GDK_KP_7: + if (aud_playlist_get_current_length(playlist) != -1) + audacious_drct_seek(CLAMP + (audacious_drct_get_time() - 5000, 0, + aud_playlist_get_current_length(playlist)) / 1000); + break; + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_9: + if (aud_playlist_get_current_length(playlist) != -1) + audacious_drct_seek(CLAMP + (audacious_drct_get_time() + 5000, 0, + aud_playlist_get_current_length(playlist)) / 1000); + break; + case GDK_KP_4: + aud_playlist_prev(playlist); + break; + case GDK_KP_6: + aud_playlist_next(playlist); + break; + case GDK_KP_Insert: +#if 0 + ui_jump_to_track(); +#endif + break; + case GDK_Return: + case GDK_KP_Enter: + case GDK_KP_5: + mainwin_play_pushed(); + break; + case GDK_space: + audacious_drct_pause(); + break; + case GDK_Escape: + mainwin_minimize_cb(); + break; + case GDK_Tab: + if (event->state & GDK_CONTROL_MASK) { + if (config.equalizer_visible) + gtk_window_present(GTK_WINDOW(equalizerwin)); + else if (config.playlist_visible) + gtk_window_present(GTK_WINDOW(playlistwin)); + } + break; + case GDK_c: + if (event->state & GDK_CONTROL_MASK) { + Playlist *playlist = aud_playlist_get_active(); + gint pos = aud_playlist_get_position(playlist); + gchar *title = aud_playlist_get_songtitle(playlist, pos); + + if (title != NULL) { + GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text(clip, title, -1); + gtk_clipboard_store(clip); + } + + return TRUE; + } + return FALSE; + default: + return FALSE; + } + + return TRUE; +} + +static void +mainwin_jump_to_time_cb(GtkWidget * widget, + GtkWidget * entry) +{ + guint min = 0, sec = 0, params; + gint time; + Playlist *playlist = aud_playlist_get_active(); + + params = sscanf(gtk_entry_get_text(GTK_ENTRY(entry)), "%u:%u", + &min, &sec); + if (params == 2) + time = (min * 60) + sec; + else if (params == 1) + time = min; + else + return; + + if (aud_playlist_get_current_length(playlist) > -1 && + time <= (aud_playlist_get_current_length(playlist) / 1000)) + { + audacious_drct_seek(time); + gtk_widget_destroy(mainwin_jtt); + } +} + + +void +mainwin_jump_to_time(void) +{ + GtkWidget *vbox, *hbox_new, *hbox_total; + GtkWidget *time_entry, *label, *bbox, *jump, *cancel; + GtkWidget *dialog; + guint tindex; + gchar time_str[10]; + + if (!audacious_drct_get_playing()) { + dialog = + gtk_message_dialog_new (GTK_WINDOW (mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Can't jump to time when no track is being played.\n")); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + return; + } + + if (mainwin_jtt) { + gtk_window_present(GTK_WINDOW(mainwin_jtt)); + return; + } + + mainwin_jtt = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint(GTK_WINDOW(mainwin_jtt), + GDK_WINDOW_TYPE_HINT_DIALOG); + + gtk_window_set_title(GTK_WINDOW(mainwin_jtt), _("Jump to Time")); + gtk_window_set_position(GTK_WINDOW(mainwin_jtt), GTK_WIN_POS_CENTER); + gtk_window_set_transient_for(GTK_WINDOW(mainwin_jtt), + GTK_WINDOW(mainwin)); + + g_signal_connect(mainwin_jtt, "destroy", + G_CALLBACK(gtk_widget_destroyed), &mainwin_jtt); + gtk_container_border_width(GTK_CONTAINER(mainwin_jtt), 10); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(mainwin_jtt), vbox); + + hbox_new = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox_new, TRUE, TRUE, 5); + + time_entry = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox_new), time_entry, FALSE, FALSE, 5); + g_signal_connect(time_entry, "activate", + G_CALLBACK(mainwin_jump_to_time_cb), time_entry); + + gtk_widget_set_size_request(time_entry, 70, -1); + label = gtk_label_new(_("minutes:seconds")); + gtk_box_pack_start(GTK_BOX(hbox_new), label, FALSE, FALSE, 5); + + hbox_total = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox_total, TRUE, TRUE, 5); + gtk_widget_show(hbox_total); + + /* FIXME: Disable display of current track length. It's not + updated when track changes */ + + label = gtk_label_new(_("Track length:")); + gtk_box_pack_start(GTK_BOX(hbox_total), label, FALSE, FALSE, 5); + + gint len = aud_playlist_get_current_length(aud_playlist_get_active()) / 1000; + g_snprintf(time_str, sizeof(time_str), "%u:%2.2u", len / 60, len % 60); + label = gtk_label_new(time_str); + + gtk_box_pack_start(GTK_BOX(hbox_total), label, FALSE, FALSE, 10); + + bbox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 0); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + + cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_container_add(GTK_CONTAINER(bbox), cancel); + g_signal_connect_swapped(cancel, "clicked", + G_CALLBACK(gtk_widget_destroy), mainwin_jtt); + + jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO); + GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT); + gtk_container_add(GTK_CONTAINER(bbox), jump); + g_signal_connect(jump, "clicked", + G_CALLBACK(mainwin_jump_to_time_cb), time_entry); + + tindex = audacious_drct_get_time() / 1000; + g_snprintf(time_str, sizeof(time_str), "%u:%2.2u", tindex / 60, + tindex % 60); + gtk_entry_set_text(GTK_ENTRY(time_entry), time_str); + + gtk_entry_select_region(GTK_ENTRY(time_entry), 0, strlen(time_str)); + + gtk_widget_show_all(mainwin_jtt); + + gtk_widget_grab_focus(time_entry); + gtk_widget_grab_default(jump); +} + +/* + * Rewritten 09/13/06: + * + * Remove all of this flaky iter/sourcelist/strsplit stuff. + * All we care about is the filepath. + * + * We can figure this out and easily pass it to g_filename_from_uri(). + * - nenolod + */ +void +mainwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, + gint y, + GtkSelectionData * selection_data, + guint info, + guint time, + gpointer user_data) +{ + Playlist *playlist = aud_playlist_get_active(); + + g_return_if_fail(selection_data != NULL); + g_return_if_fail(selection_data->data != NULL); +#if 0 + if (aud_str_has_prefix_nocase((gchar *) selection_data->data, "fonts:///")) + { + gchar *path = (gchar *) selection_data->data; + gchar *decoded = g_filename_from_uri(path, NULL, NULL); + + if (decoded == NULL) + return; + + aud_cfg->playlist_font = g_strconcat(decoded, strrchr(aud_cfg->playlist_font, ' '), NULL); + ui_skinned_playlist_set_font(aud_cfg->playlist_font); + playlistwin_update_list(playlist); + + g_free(decoded); + + return; + } + + /* perhaps make suffix check case-insensitive -- desowin */ + if (aud_str_has_prefix_nocase((char*)selection_data->data, "file:///")) { + if (str_has_suffix_nocase((char*)selection_data->data, ".wsz\r\n") || + str_has_suffix_nocase((char*)selection_data->data, ".zip\r\n")) { + on_skin_view_drag_data_received(GTK_WIDGET(user_data), context, x, y, selection_data, info, time, NULL); + return; + } + } +#endif + aud_playlist_clear(playlist); + aud_playlist_add_url(playlist, (gchar *) selection_data->data); + audacious_drct_initiate(); +} + +static void +on_add_url_add_clicked(GtkWidget * widget, + GtkWidget * entry) +{ + const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); + if (text && *text) + aud_playlist_add_url(aud_playlist_get_active(), text); +} + +static void +on_add_url_ok_clicked(GtkWidget * widget, + GtkWidget * entry) +{ + Playlist *playlist = aud_playlist_get_active(); + + const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); + if (text && *text) + { + aud_playlist_clear(playlist); + aud_playlist_add_url(playlist, text); + audacious_drct_initiate(); + } +} + +static void +on_visibility_warning_toggle(GtkToggleButton *tbt, gpointer unused) +{ + config.warn_about_win_visibility = !gtk_toggle_button_get_active(tbt); +} + +static void +on_visibility_warning_response(GtkDialog *dlg, gint r_id, gpointer unused) +{ + switch (r_id) + { + case GTK_RESPONSE_OK: + mainwin_show(TRUE); + break; + case GTK_RESPONSE_CANCEL: + default: + break; + } + gtk_widget_destroy(GTK_WIDGET(dlg)); +} + +void +mainwin_show_visibility_warning(void) +{ + if (config.warn_about_win_visibility) + { + GtkWidget *label, *checkbt, *vbox; + GtkWidget *warning_dlg = + gtk_dialog_new_with_buttons( _("Audacious - visibility warning") , + GTK_WINDOW(mainwin) , + GTK_DIALOG_DESTROY_WITH_PARENT , + _("Show main player window") , + GTK_RESPONSE_OK , _("Ignore") , + GTK_RESPONSE_CANCEL , NULL ); + + vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(vbox) , 4 ); + gtk_box_pack_start( GTK_BOX(GTK_DIALOG(warning_dlg)->vbox) , vbox , TRUE , TRUE , 0 ); + label = gtk_label_new( _("Audacious has been started with all of its windows hidden.\n" + "You may want to show the player window again to control Audacious; " + "otherwise, you'll have to control it remotely via audtool or " + "enabled plugins (such as the statusicon plugin).") ); + gtk_label_set_line_wrap( GTK_LABEL(label) , TRUE ); + gtk_misc_set_alignment( GTK_MISC(label) , 0.0 , 0.0 ); + checkbt = gtk_check_button_new_with_label( _("Always ignore, show/hide is controlled remotely") ); + gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0 ); + gtk_box_pack_start( GTK_BOX(vbox) , checkbt , TRUE , TRUE , 0 ); + g_signal_connect( G_OBJECT(checkbt) , "toggled" , + G_CALLBACK(on_visibility_warning_toggle) , NULL ); + g_signal_connect( G_OBJECT(warning_dlg) , "response" , + G_CALLBACK(on_visibility_warning_response) , NULL ); + gtk_widget_show_all(warning_dlg); + } +} + +static void +on_broken_gtk_engine_warning_toggle(GtkToggleButton *tbt, gpointer unused) +{ + config.warn_about_broken_gtk_engines = !gtk_toggle_button_get_active(tbt); +} + +void +ui_main_check_theme_engine(void) +{ + GtkSettings *settings; + GtkWidget *widget; + gchar *theme = NULL; + + widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_ensure_style(widget); + + settings = gtk_settings_get_default(); + g_object_get(G_OBJECT(settings), "gtk-theme-name", &theme, NULL); + gtk_widget_destroy(widget); + + if (theme == NULL) + return; + + if (g_ascii_strcasecmp(theme, "Qt")) + { + g_free(theme); + return; + } + + if (config.warn_about_broken_gtk_engines) + { + gchar *msg; + GtkWidget *label, *checkbt, *vbox; + GtkWidget *warning_dlg = + gtk_dialog_new_with_buttons( _("Audacious - broken GTK engine usage warning") , + GTK_WINDOW(mainwin) , GTK_DIALOG_DESTROY_WITH_PARENT , + GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL ); + vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(vbox) , 4 ); + gtk_box_pack_start( GTK_BOX(GTK_DIALOG(warning_dlg)->vbox) , vbox , + TRUE , TRUE , 0 ); + + msg = g_strdup_printf(_("<big><b>Broken GTK engine in use</b></big>\n\n" + "Audacious has detected that you are using a broken GTK engine.\n\n" + "The theme engine you are using, <i>%s</i>, is incompatible with some of the features " + "used by modern skins. The incompatible features have been disabled for this session.\n\n" + "To use these features, please consider using a different GTK theme engine."), theme); + label = gtk_label_new(msg); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); + g_free(msg); + + gtk_label_set_line_wrap( GTK_LABEL(label) , TRUE ); + gtk_misc_set_alignment( GTK_MISC(label) , 0.0 , 0.0 ); + checkbt = gtk_check_button_new_with_label( _("Do not display this warning again") ); + gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0 ); + gtk_box_pack_start( GTK_BOX(vbox) , checkbt , TRUE , TRUE , 0 ); + g_signal_connect( G_OBJECT(checkbt) , "toggled" , + G_CALLBACK(on_broken_gtk_engine_warning_toggle) , NULL ); + g_signal_connect( G_OBJECT(warning_dlg) , "response" , + G_CALLBACK(gtk_widget_destroy) , NULL ); + gtk_widget_show_all(warning_dlg); + gtk_window_stick(GTK_WINDOW(warning_dlg)); + } + + config.disable_inline_gtk = TRUE; + + g_free(theme); +} + +void +mainwin_show_add_url_window(void) +{ +#if 0 + static GtkWidget *url_window = NULL; + + if (!url_window) { + url_window = + util_add_url_dialog_new(_("Enter location to play:"), + G_CALLBACK(on_add_url_ok_clicked), + G_CALLBACK(on_add_url_add_clicked)); + gtk_window_set_transient_for(GTK_WINDOW(url_window), + GTK_WINDOW(mainwin)); + g_signal_connect(url_window, "destroy", + G_CALLBACK(gtk_widget_destroyed), + &url_window); + } + + gtk_window_present(GTK_WINDOW(url_window)); +#endif +} + +static void +check_set( GtkActionGroup * action_group , + const gchar * action_name , + gboolean is_on ) +{ + /* check_set noew uses gtkaction */ + GtkAction *action = gtk_action_group_get_action( action_group , action_name ); + if ( action != NULL ) + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , is_on ); + return; +} + +void +mainwin_eject_pushed(void) +{ + run_filebrowser(PLAY_BUTTON); +} + +void +mainwin_rev_pushed(void) +{ + g_get_current_time(&cb_time); + + seek_initial_pos = ui_skinned_horizontal_slider_get_position(mainwin_position); + seek_state = MAINWIN_SEEK_REV; + mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, + (GSourceFunc) mainwin_idle_func, NULL); +} + +void +mainwin_rev_release(void) +{ + GTimeVal now_time; + GTimeVal delta_time; + gulong now_dur; + + g_get_current_time(&now_time); + + delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; + delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; + + now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); + + if ( now_dur <= TRISTATE_THRESHOLD ) + { + /* interpret as 'skip to previous song' */ + aud_playlist_prev(aud_playlist_get_active()); + } + else + { + /* interpret as 'seek' */ + mainwin_position_release_cb( mainwin_position, ui_skinned_horizontal_slider_get_position(mainwin_position) ); + } + + seek_state = MAINWIN_SEEK_NIL; + + g_source_remove(mainwin_timeout_id); + mainwin_timeout_id = 0; +} + +void +mainwin_fwd_pushed(void) +{ + g_get_current_time(&cb_time); + + seek_initial_pos = ui_skinned_horizontal_slider_get_position(mainwin_position); + seek_state = MAINWIN_SEEK_FWD; + mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, + (GSourceFunc) mainwin_idle_func, NULL); +} + +void +mainwin_fwd_release(void) +{ + GTimeVal now_time; + GTimeVal delta_time; + gulong now_dur; + + g_get_current_time(&now_time); + + delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; + delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; + + now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); + + if ( now_dur <= TRISTATE_THRESHOLD ) + { + /* interpret as 'skip to next song' */ + aud_playlist_next(aud_playlist_get_active()); + } + else + { + /* interpret as 'seek' */ + mainwin_position_release_cb( mainwin_position, ui_skinned_horizontal_slider_get_position(mainwin_position) ); + } + + seek_state = MAINWIN_SEEK_NIL; + + g_source_remove(mainwin_timeout_id); + mainwin_timeout_id = 0; +} + +void +mainwin_play_pushed(void) +{ + if (ab_position_a != -1) + audacious_drct_seek(ab_position_a / 1000); + if (audacious_drct_get_paused()) { + audacious_drct_pause(); + return; + } + + if (aud_playlist_get_length(aud_playlist_get_active())) + audacious_drct_initiate(); + else + mainwin_eject_pushed(); +} + +void +mainwin_stop_pushed(void) +{ + audacious_drct_stop(); + mainwin_clear_song_info(); + ab_position_a = ab_position_b = -1; +} + +void +mainwin_shuffle_pushed(gboolean toggled) +{ + check_set( toggleaction_group_others , "playback shuffle" , toggled ); +} + +void mainwin_shuffle_pushed_cb(void) { + mainwin_shuffle_pushed(UI_SKINNED_BUTTON(mainwin_shuffle)->inside); +} + +void +mainwin_repeat_pushed(gboolean toggled) +{ + check_set( toggleaction_group_others , "playback repeat" , toggled ); +} + +void mainwin_repeat_pushed_cb(void) { + mainwin_repeat_pushed(UI_SKINNED_BUTTON(mainwin_repeat)->inside); +} + +void mainwin_equalizer_pushed_cb(void) { + mainwin_eq_pushed(UI_SKINNED_BUTTON(mainwin_eq)->inside); +} + +void mainwin_playlist_pushed_cb(void) { + mainwin_pl_pushed(UI_SKINNED_BUTTON(mainwin_pl)->inside); +} + +void +mainwin_eq_pushed(gboolean toggled) +{ + equalizerwin_show(toggled); +} + +void +mainwin_pl_pushed(gboolean toggled) +{ + if (toggled) + playlistwin_show(); + else + playlistwin_hide(); +} + +gint +mainwin_spos_frame_cb(gint pos) +{ + if (mainwin_sposition) { + gint x = 0; + if (pos < 6) + x = 17; + else if (pos < 9) + x = 20; + else + x = 23; + + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->knob_nx = x; + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->knob_px = x; + } + return 1; +} + +void +mainwin_spos_motion_cb(GtkWidget *widget, gint pos) +{ + gint time; + gchar *time_msg; + Playlist *playlist = aud_playlist_get_active(); + + pos--; + + time = ((aud_playlist_get_current_length(playlist) / 1000) * pos) / 12; + + if (config.timer_mode == TIMER_REMAINING) { + time = (aud_playlist_get_current_length(playlist) / 1000) - time; + time_msg = g_strdup_printf("-%2.2d", time / 60); + ui_skinned_textbox_set_text(mainwin_stime_min, time_msg); + g_free(time_msg); + } + else { + time_msg = g_strdup_printf(" %2.2d", time / 60); + ui_skinned_textbox_set_text(mainwin_stime_min, time_msg); + g_free(time_msg); + } + + time_msg = g_strdup_printf("%2.2d", time % 60); + ui_skinned_textbox_set_text(mainwin_stime_sec, time_msg); + g_free(time_msg); +} + +void +mainwin_spos_release_cb(GtkWidget *widget, gint pos) +{ + audacious_drct_seek(((aud_playlist_get_current_length(aud_playlist_get_active()) / 1000) * + (pos - 1)) / 12); +} + +void +mainwin_position_motion_cb(GtkWidget *widget, gint pos) +{ + gint length, time; + gchar *seek_msg; + + length = aud_playlist_get_current_length(aud_playlist_get_active()) / 1000; + time = (length * pos) / 219; + seek_msg = g_strdup_printf(_("Seek to: %d:%-2.2d/%d:%-2.2d (%d%%)"), + time / 60, time % 60, + length / 60, length % 60, + (length != 0) ? (time * 100) / length : 0); + mainwin_lock_info_text(seek_msg); + g_free(seek_msg); +} + +void +mainwin_position_release_cb(GtkWidget *widget, gint pos) +{ + gint length, time; + + length = audacious_drct_get_length(); + time = (length * pos) / 219; + audacious_drct_seek(time); + mainwin_release_info_text(); +} + +gint +mainwin_volume_frame_cb(gint pos) +{ + return (gint) rint((pos / 52.0) * 28); +} + +void +mainwin_adjust_volume_motion(gint v) +{ + gchar *volume_msg; + + volume_msg = g_strdup_printf(_("Volume: %d%%"), v); + mainwin_lock_info_text(volume_msg); + g_free(volume_msg); + + if (balance < 0) + audacious_drct_set_volume(v, (v * (100 - abs(balance))) / 100); + else if (balance > 0) + audacious_drct_set_volume((v * (100 - abs(balance))) / 100, v); + else + audacious_drct_set_volume(v, v); +} + +void +mainwin_adjust_volume_release(void) +{ + mainwin_release_info_text(); +} + +void +mainwin_adjust_balance_motion(gint b) +{ + gchar *balance_msg; + gint v, pvl, pvr; + + balance = b; + aud_input_get_volume(&pvl, &pvr); + v = MAX(pvl, pvr); + if (b < 0) { + balance_msg = g_strdup_printf(_("Balance: %d%% left"), -b); + audacious_drct_set_volume(v, (gint) rint(((100 + b) / 100.0) * v)); + } + else if (b == 0) { + balance_msg = g_strdup_printf(_("Balance: center")); + audacious_drct_set_volume(v, v); + } + else { /* b > 0 */ + balance_msg = g_strdup_printf(_("Balance: %d%% right"), b); + audacious_drct_set_volume((gint) rint(((100 - b) / 100.0) * v), v); + } + mainwin_lock_info_text(balance_msg); + g_free(balance_msg); +} + +void +mainwin_adjust_balance_release(void) +{ + mainwin_release_info_text(); +} + +void +mainwin_set_volume_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(mainwin_volume, (gint) rint((percent * 51) / 100.0)); +} + +void +mainwin_set_balance_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(mainwin_balance, (gint) rint(((percent * 12) / 100.0) + 12)); +} + +void +mainwin_volume_motion_cb(GtkWidget *widget, gint pos) +{ + + gint vol = (pos * 100) / 51; + mainwin_adjust_volume_motion(vol); + equalizerwin_set_volume_slider(vol); +} + +gboolean +mainwin_volume_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_volume_release(); + return FALSE; +} + +gint +mainwin_balance_frame_cb(gint pos) +{ + return ((abs(pos - 12) * 28) / 13); +} + +void +mainwin_balance_motion_cb(GtkWidget *widget, gint pos) +{ + gint bal = ((pos - 12) * 100) / 12; + mainwin_adjust_balance_motion(bal); + equalizerwin_set_balance_slider(bal); +} + +void +mainwin_balance_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_volume_release(); +} + +void +mainwin_set_volume_diff(gint diff) +{ + gint vl, vr, vol; + + aud_input_get_volume(&vl, &vr); + vol = MAX(vl, vr); + vol = CLAMP(vol + diff, 0, 100); + + mainwin_adjust_volume_motion(vol); + mainwin_set_volume_slider(vol); + equalizerwin_set_volume_slider(vol); + + if (mainwin_volume_release_timeout) + g_source_remove(mainwin_volume_release_timeout); + mainwin_volume_release_timeout = + g_timeout_add(700, (GSourceFunc)(mainwin_volume_release_cb), NULL); +} + +void +mainwin_set_balance_diff(gint diff) +{ + gint b; + b = CLAMP(balance + diff, -100, 100); + mainwin_adjust_balance_motion(b); + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); +} + +void +mainwin_show(gboolean show) +{ + if (show) + mainwin_real_show(); + else + mainwin_real_hide(); +} + +void +mainwin_real_show(void) +{ + config.player_visible = TRUE; + + check_set( toggleaction_group_others , "show player" , TRUE ); + + if (config.player_shaded) + ui_vis_clear_data(mainwin_vis); + + if (config.show_wm_decorations) { + if (config.player_x != -1 && config.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), config.player_x, config.player_y); + + gtk_widget_show(mainwin); + return; + } + + if (config.player_x != -1 && config.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), config.player_x, config.player_y); + + mainwin_refresh_hints(); + gtk_window_present(GTK_WINDOW(mainwin)); +} + +void +mainwin_real_hide(void) +{ + + check_set( toggleaction_group_others , "show player", FALSE); + + if (config.player_shaded) + ui_svis_clear_data(mainwin_svis); + + gtk_widget_hide(mainwin); + + config.player_visible = FALSE; +} + + +void +mainwin_set_stopaftersong(gboolean stop) +{ + aud_cfg->stopaftersong = stop; + check_set(toggleaction_group_others, "stop after current song", aud_cfg->stopaftersong); +} + +void +mainwin_set_noplaylistadvance(gboolean no_advance) +{ + aud_cfg->no_playlist_advance = no_advance; + check_set(toggleaction_group_others, "playback no playlist advance", aud_cfg->no_playlist_advance); +} + +static void +mainwin_set_scaled(gboolean scaled) +{ + gint height; + + if (config.player_shaded) + height = MAINWIN_SHADED_HEIGHT; + else + height = aud_active_skin->properties.mainwin_height; + + dock_window_resize(GTK_WINDOW(mainwin), config.player_shaded ? MAINWIN_SHADED_WIDTH : aud_active_skin->properties.mainwin_width, + config.player_shaded ? MAINWIN_SHADED_HEIGHT : aud_active_skin->properties.mainwin_height, + aud_active_skin->properties.mainwin_width * config.scale_factor , aud_active_skin->properties.mainwin_height * config.scale_factor); + + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + g_signal_emit_by_name(child, "toggle-scaled"); + } + + mainwin_refresh_hints(); + gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + config.player_shaded), 0, 0); +} + +void +set_scaled(gboolean scaled) +{ + config.scaled = scaled; + + mainwin_set_scaled(scaled); + + if (config.eq_scaled_linked) + equalizerwin_set_scaled(scaled); +} + + + +void +mainwin_general_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + Playlist *playlist = aud_playlist_get_active(); + + switch (action) { +#if 0 + case MAINWIN_GENERAL_PREFS: + show_prefs_window(); + break; + case MAINWIN_GENERAL_ABOUT: + show_about_window(); + break; +#endif + case MAINWIN_GENERAL_PLAYFILE: + run_filebrowser(NO_PLAY_BUTTON); + break; + case MAINWIN_GENERAL_PLAYLOCATION: + mainwin_show_add_url_window(); + break; +#if 0 + case MAINWIN_GENERAL_FILEINFO: + ui_fileinfo_show_current(playlist); + break; +#endif + case MAINWIN_GENERAL_FOCUSPLWIN: + gtk_window_present(GTK_WINDOW(playlistwin)); + break; + case MAINWIN_GENERAL_SHOWMWIN: + mainwin_show(GTK_CHECK_MENU_ITEM(item)->active); + break; + case MAINWIN_GENERAL_SHOWPLWIN: + if (GTK_CHECK_MENU_ITEM(item)->active) + playlistwin_show(); + else + playlistwin_hide(); + break; + case MAINWIN_GENERAL_SHOWEQWIN: + if (GTK_CHECK_MENU_ITEM(item)->active) + equalizerwin_real_show(); + else + equalizerwin_real_hide(); + break; + case MAINWIN_GENERAL_PREV: + aud_playlist_prev(playlist); + break; + case MAINWIN_GENERAL_PLAY: + mainwin_play_pushed(); + break; + case MAINWIN_GENERAL_PAUSE: + audacious_drct_pause(); + break; + case MAINWIN_GENERAL_STOP: + mainwin_stop_pushed(); + break; + case MAINWIN_GENERAL_NEXT: + aud_playlist_next(playlist); + break; +#if 0 + case MAINWIN_GENERAL_BACK5SEC: + if (audacious_drct_get_playing() + && aud_playlist_get_current_length(playlist) != -1) + playback_seek_relative(-5); + break; + case MAINWIN_GENERAL_FWD5SEC: + if (audacious_drct_get_playing() + && aud_playlist_get_current_length(playlist) != -1) + playback_seek_relative(5); + break; +#endif + case MAINWIN_GENERAL_START: + aud_playlist_set_position(playlist, 0); + break; + case MAINWIN_GENERAL_JTT: + mainwin_jump_to_time(); + break; + case MAINWIN_GENERAL_JTF: +#if 0 + ui_jump_to_track(); +#endif + break; + case MAINWIN_GENERAL_EXIT: + mainwin_quit_cb(); + break; + case MAINWIN_GENERAL_SETAB: + if (aud_playlist_get_current_length(playlist) != -1) { + if (ab_position_a == -1) { + ab_position_a = audacious_drct_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("'Loop-Point A Position' set."); + } else if (ab_position_b == -1) { + int time = audacious_drct_get_time(); + if (time > ab_position_a) + ab_position_b = time; + mainwin_release_info_text(); + } else { + ab_position_a = audacious_drct_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("'Loop-Point A Position' reset."); + } + } + break; + case MAINWIN_GENERAL_CLEARAB: + if (aud_playlist_get_current_length(playlist) != -1) { + ab_position_a = ab_position_b = -1; + mainwin_release_info_text(); + } + break; + case MAINWIN_GENERAL_NEW_PL: + { + Playlist *new_pl = aud_playlist_new(); + aud_playlist_add_playlist(new_pl); + aud_playlist_select_playlist(new_pl); + } + break; + case MAINWIN_GENERAL_PREV_PL: + aud_playlist_select_prev(); + break; + case MAINWIN_GENERAL_NEXT_PL: + aud_playlist_select_next(); + break; + } +} + +static void +mainwin_mr_change(GtkWidget *widget, MenuRowItem i) +{ + switch (i) { + case MENUROW_OPTIONS: + mainwin_lock_info_text(_("Options Menu")); + break; + case MENUROW_ALWAYS: + if (UI_SKINNED_MENUROW(mainwin_menurow)->always_selected) + mainwin_lock_info_text(_("Disable 'Always On Top'")); + else + mainwin_lock_info_text(_("Enable 'Always On Top'")); + break; + case MENUROW_FILEINFOBOX: + mainwin_lock_info_text(_("File Info Box")); + break; + case MENUROW_SCALE: + if (UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected) + mainwin_lock_info_text(_("Disable 'GUI Scaling'")); + else + mainwin_lock_info_text(_("Enable 'GUI Scaling'")); + break; + case MENUROW_VISUALIZATION: + mainwin_lock_info_text(_("Visualization Menu")); + break; + case MENUROW_NONE: + break; + } +} + +static void +mainwin_mr_release(GtkWidget *widget, MenuRowItem i, GdkEventButton *event) +{ + switch (i) { + case MENUROW_OPTIONS: + ui_manager_popup_menu_show(GTK_MENU(mainwin_view_menu), + event->x_root, event->y_root, 1, + event->time); + break; + case MENUROW_ALWAYS: + gtk_toggle_action_set_active( + GTK_TOGGLE_ACTION(gtk_action_group_get_action( + toggleaction_group_others , "view always on top" )) , + UI_SKINNED_MENUROW(mainwin_menurow)->always_selected ); + break; + case MENUROW_FILEINFOBOX: +#if 0 + ui_fileinfo_show_current(aud_playlist_get_active()); +#endif + break; + case MENUROW_SCALE: + gtk_toggle_action_set_active( + GTK_TOGGLE_ACTION(gtk_action_group_get_action( + toggleaction_group_others , "view scaled" )) , + UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected ); + break; + case MENUROW_VISUALIZATION: + ui_manager_popup_menu_show(GTK_MENU(mainwin_visualization_menu), + event->x_root, event->y_root, 1, + event->time); + break; + case MENUROW_NONE: + break; + } + + mainwin_release_info_text(); +} + +void +run_no_output_device_dialog(gpointer hook_data, gpointer user_data) +{ + const gchar *markup = + N_("<b><big>Couldn't open audio.</big></b>\n\n" + "Please check that:\n" + "1. You have the correct output plugin selected.\n" + "2. No other programs is blocking the soundcard.\n" + "3. Your soundcard is configured properly.\n"); + + GDK_THREADS_ENTER(); + GtkWidget *dialog = + gtk_message_dialog_new_with_markup(GTK_WINDOW(mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _(markup)); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + GDK_THREADS_LEAVE(); +} + +void +ui_main_set_initial_volume(void) +{ + gint vl, vr, b, v; + + aud_input_get_volume(&vl, &vr); + + vl = CLAMP(vl, 0, 100); + vr = CLAMP(vr, 0, 100); + v = MAX(vl, vr); + if (vl > vr) + b = (gint) rint(((gdouble) vr / vl) * 100) - 100; + else if (vl < vr) + b = 100 - (gint) rint(((gdouble) vl / vr) * 100); + else + b = 0; + + mainwin_set_volume_slider(v); + equalizerwin_set_volume_slider(v); + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); +} + +static void +set_timer_mode(TimerMode mode) +{ + if (mode == TIMER_ELAPSED) + check_set(radioaction_group_viewtime, "view time elapsed", TRUE); + else + check_set(radioaction_group_viewtime, "view time remaining", TRUE); +} + +static void +set_timer_mode_menu_cb(TimerMode mode) +{ + config.timer_mode = mode; +} + +gboolean +change_timer_mode_cb(GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1) { + change_timer_mode(); + } else if (event->button == 3) + return FALSE; + + return TRUE; +} + +static void change_timer_mode(void) { + if (config.timer_mode == TIMER_ELAPSED) + set_timer_mode(TIMER_REMAINING); + else + set_timer_mode(TIMER_ELAPSED); + if (audacious_drct_get_playing()) + mainwin_update_song_info(); +} + +static void +mainwin_aud_playlist_prev(void) +{ + aud_playlist_prev(aud_playlist_get_active()); +} + +static void +mainwin_aud_playlist_next(void) +{ + aud_playlist_next(aud_playlist_get_active()); +} + +void +mainwin_setup_menus(void) +{ + set_timer_mode(config.timer_mode); + + /* View menu */ + + check_set(toggleaction_group_others, "view always on top", config.always_on_top); + check_set(toggleaction_group_others, "view put on all workspaces", config.sticky); + check_set(toggleaction_group_others, "roll up player", config.player_shaded); + check_set(toggleaction_group_others, "roll up playlist editor", config.playlist_shaded); + check_set(toggleaction_group_others, "roll up equalizer", config.equalizer_shaded); + check_set(toggleaction_group_others, "view easy move", config.easy_move); + check_set(toggleaction_group_others, "view scaled", config.scaled); + + /* Songname menu */ + + check_set(toggleaction_group_others, "autoscroll songname", config.autoscroll); + check_set(toggleaction_group_others, "stop after current song", aud_cfg->stopaftersong); + + /* Playback menu */ + + check_set(toggleaction_group_others, "playback repeat", aud_cfg->repeat); + check_set(toggleaction_group_others, "playback shuffle", aud_cfg->shuffle); + check_set(toggleaction_group_others, "playback no playlist advance", aud_cfg->no_playlist_advance); + + /* Visualization menu */ + + switch ( config.vis_type ) + { + case VIS_ANALYZER: + check_set(radioaction_group_vismode, "vismode analyzer", TRUE); + break; + case VIS_SCOPE: + check_set(radioaction_group_vismode, "vismode scope", TRUE); + break; + case VIS_VOICEPRINT: + check_set(radioaction_group_vismode, "vismode voiceprint", TRUE); + break; + case VIS_OFF: + default: + check_set(radioaction_group_vismode, "vismode off", TRUE); + break; + } + + switch ( config.analyzer_mode ) + { + case ANALYZER_FIRE: + check_set(radioaction_group_anamode, "anamode fire", TRUE); + break; + case ANALYZER_VLINES: + check_set(radioaction_group_anamode, "anamode vertical lines", TRUE); + break; + case ANALYZER_NORMAL: + default: + check_set(radioaction_group_anamode, "anamode normal", TRUE); + break; + } + + switch ( config.analyzer_type ) + { + case ANALYZER_BARS: + check_set(radioaction_group_anatype, "anatype bars", TRUE); + break; + case ANALYZER_LINES: + default: + check_set(radioaction_group_anatype, "anatype lines", TRUE); + break; + } + + check_set(toggleaction_group_others, "anamode peaks", config.analyzer_peaks ); + + switch ( config.scope_mode ) + { + case SCOPE_LINE: + check_set(radioaction_group_scomode, "scomode line", TRUE); + break; + case SCOPE_SOLID: + check_set(radioaction_group_scomode, "scomode solid", TRUE); + break; + case SCOPE_DOT: + default: + check_set(radioaction_group_scomode, "scomode dot", TRUE); + break; + } + + switch ( config.voiceprint_mode ) + { + case VOICEPRINT_FIRE: + check_set(radioaction_group_vprmode, "vprmode fire", TRUE); + break; + case VOICEPRINT_ICE: + check_set(radioaction_group_vprmode, "vprmode ice", TRUE); + break; + case VOICEPRINT_NORMAL: + default: + check_set(radioaction_group_vprmode, "vprmode normal", TRUE); + break; + } + + switch ( config.vu_mode ) + { + case VU_SMOOTH: + check_set(radioaction_group_wshmode, "wshmode smooth", TRUE); + break; + case VU_NORMAL: + default: + check_set(radioaction_group_wshmode, "wshmode normal", TRUE); + break; + } + + switch ( config.vis_refresh ) + { + case REFRESH_HALF: + check_set(radioaction_group_refrate, "refrate half", TRUE); + break; + case REFRESH_QUARTER: + check_set(radioaction_group_refrate, "refrate quarter", TRUE); + break; + case REFRESH_EIGTH: + check_set(radioaction_group_refrate, "refrate eighth", TRUE); + break; + case REFRESH_FULL: + default: + check_set(radioaction_group_refrate, "refrate full", TRUE); + break; + } + + switch ( config.analyzer_falloff ) + { + case FALLOFF_SLOW: + check_set(radioaction_group_anafoff, "anafoff slow", TRUE); + break; + case FALLOFF_MEDIUM: + check_set(radioaction_group_anafoff, "anafoff medium", TRUE); + break; + case FALLOFF_FAST: + check_set(radioaction_group_anafoff, "anafoff fast", TRUE); + break; + case FALLOFF_FASTEST: + check_set(radioaction_group_anafoff, "anafoff fastest", TRUE); + break; + case FALLOFF_SLOWEST: + default: + check_set(radioaction_group_anafoff, "anafoff slowest", TRUE); + break; + } + + switch ( config.peaks_falloff ) + { + case FALLOFF_SLOW: + check_set(radioaction_group_peafoff, "peafoff slow", TRUE); + break; + case FALLOFF_MEDIUM: + check_set(radioaction_group_peafoff, "peafoff medium", TRUE); + break; + case FALLOFF_FAST: + check_set(radioaction_group_peafoff, "peafoff fast", TRUE); + break; + case FALLOFF_FASTEST: + check_set(radioaction_group_peafoff, "peafoff fastest", TRUE); + break; + case FALLOFF_SLOWEST: + default: + check_set(radioaction_group_peafoff, "peafoff slowest", TRUE); + break; + } +} + +static void mainwin_info_double_clicked_cb(void) { +#if 0 + ui_fileinfo_show_current(aud_playlist_get_active()); +#endif +} + +static void +mainwin_info_right_clicked_cb(GtkWidget *widget, GdkEventButton *event) +{ + ui_manager_popup_menu_show(GTK_MENU(mainwin_songname_menu), + event->x_root, event->y_root, 3, event->time); +} + +static void +mainwin_create_widgets(void) +{ + mainwin_menubtn = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_menubtn, SKINNED_WINDOW(mainwin)->fixed, + 6, 3, 9, 9, 0, 0, 0, 9, SKIN_TITLEBAR); + g_signal_connect(mainwin_menubtn, "clicked", mainwin_menubtn_cb, NULL ); + + mainwin_minimize = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_minimize, SKINNED_WINDOW(mainwin)->fixed, + 244, 3, 9, 9, 9, 0, 9, 9, SKIN_TITLEBAR); + g_signal_connect(mainwin_minimize, "clicked", mainwin_minimize_cb, NULL ); + + mainwin_shade = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_shade, SKINNED_WINDOW(mainwin)->fixed, + 254, 3, 9, 9, 0, + config.player_shaded ? 27 : 18, 9, config.player_shaded ? 27 : 18, SKIN_TITLEBAR); + g_signal_connect(mainwin_shade, "clicked", mainwin_shade_toggle, NULL ); + + mainwin_close = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_close, SKINNED_WINDOW(mainwin)->fixed, + 264, 3, 9, 9, 18, 0, 18, 9, SKIN_TITLEBAR); + g_signal_connect(mainwin_close, "clicked", mainwin_quit_cb, NULL ); + + mainwin_rew = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_rew, SKINNED_WINDOW(mainwin)->fixed, + 16, 88, 23, 18, 0, 0, 0, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_rew, "pressed", mainwin_rev_pushed, NULL); + g_signal_connect(mainwin_rew, "released", mainwin_rev_release, NULL); + + mainwin_fwd = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_fwd, SKINNED_WINDOW(mainwin)->fixed, + 108, 88, 22, 18, 92, 0, 92, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_fwd, "pressed", mainwin_fwd_pushed, NULL); + g_signal_connect(mainwin_fwd, "released", mainwin_fwd_release, NULL); + + mainwin_play = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_play, SKINNED_WINDOW(mainwin)->fixed, + 39, 88, 23, 18, 23, 0, 23, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_play, "clicked", mainwin_play_pushed, NULL ); + + mainwin_pause = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_pause, SKINNED_WINDOW(mainwin)->fixed, + 62, 88, 23, 18, 46, 0, 46, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_pause, "clicked", audacious_drct_pause, NULL ); + + mainwin_stop = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_stop, SKINNED_WINDOW(mainwin)->fixed, + 85, 88, 23, 18, 69, 0, 69, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_stop, "clicked", mainwin_stop_pushed, NULL ); + + mainwin_eject = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_eject, SKINNED_WINDOW(mainwin)->fixed, + 136, 89, 22, 16, 114, 0, 114, 16, SKIN_CBUTTONS); + g_signal_connect(mainwin_eject, "clicked", mainwin_eject_pushed, NULL); + + mainwin_srew = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_srew, SKINNED_WINDOW(mainwin)->fixed, 169, 4, 8, 7); + g_signal_connect(mainwin_srew, "clicked", mainwin_aud_playlist_prev, NULL); + + mainwin_splay = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_splay, SKINNED_WINDOW(mainwin)->fixed, 177, 4, 10, 7); + g_signal_connect(mainwin_splay, "clicked", mainwin_play_pushed, NULL); + + mainwin_spause = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_spause, SKINNED_WINDOW(mainwin)->fixed, 187, 4, 10, 7); + g_signal_connect(mainwin_spause, "clicked", audacious_drct_pause, NULL); + + mainwin_sstop = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_sstop, SKINNED_WINDOW(mainwin)->fixed, 197, 4, 9, 7); + g_signal_connect(mainwin_sstop, "clicked", mainwin_stop_pushed, NULL); + + mainwin_sfwd = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_sfwd, SKINNED_WINDOW(mainwin)->fixed, 206, 4, 8, 7); + g_signal_connect(mainwin_sfwd, "clicked", mainwin_aud_playlist_next, NULL); + + mainwin_seject = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_seject, SKINNED_WINDOW(mainwin)->fixed, 216, 4, 9, 7); + g_signal_connect(mainwin_seject, "clicked", mainwin_eject_pushed, NULL); + + mainwin_shuffle = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_shuffle, SKINNED_WINDOW(mainwin)->fixed, + 164, 89, 46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP); + g_signal_connect(mainwin_shuffle, "clicked", mainwin_shuffle_pushed_cb, NULL); + + mainwin_repeat = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_repeat, SKINNED_WINDOW(mainwin)->fixed, + 210, 89, 28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP); + g_signal_connect(mainwin_repeat, "clicked", mainwin_repeat_pushed_cb, NULL); + + mainwin_eq = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_eq, SKINNED_WINDOW(mainwin)->fixed, + 219, 58, 23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP); + g_signal_connect(mainwin_eq, "clicked", mainwin_equalizer_pushed_cb, NULL); + UI_SKINNED_BUTTON(mainwin_eq)->inside = config.equalizer_visible; + + mainwin_pl = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_pl, SKINNED_WINDOW(mainwin)->fixed, + 242, 58, 23, 12, 23, 61, 69, 61, 23, 73, 69, 73, SKIN_SHUFREP); + g_signal_connect(mainwin_pl, "clicked", mainwin_playlist_pushed_cb, NULL); + UI_SKINNED_BUTTON(mainwin_pl)->inside = config.playlist_visible; + + mainwin_info = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 112, 27, 153, 1, SKIN_TEXT); + ui_skinned_textbox_set_scroll(mainwin_info, config.autoscroll); + ui_skinned_textbox_set_xfont(mainwin_info, !config.mainwin_use_bitmapfont, aud_cfg->mainwin_font); + g_signal_connect(mainwin_info, "double-clicked", mainwin_info_double_clicked_cb, NULL); + g_signal_connect(mainwin_info, "right-clicked", G_CALLBACK(mainwin_info_right_clicked_cb), NULL); + + mainwin_othertext = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 112, 43, 153, 1, SKIN_TEXT); + + mainwin_rate_text = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 111, 43, 15, 0, SKIN_TEXT); + + mainwin_freq_text = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 156, 43, 10, 0, SKIN_TEXT); + + mainwin_menurow = ui_skinned_menurow_new(SKINNED_WINDOW(mainwin)->fixed, 10, 22, 304, 0, 304, 44, SKIN_TITLEBAR); + g_signal_connect(mainwin_menurow, "change", G_CALLBACK(mainwin_mr_change), NULL); + g_signal_connect(mainwin_menurow, "release", G_CALLBACK(mainwin_mr_release), NULL); + + mainwin_volume = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 107, 57, 68, + 13, 15, 422, 0, 422, 14, 11, 15, 0, 0, 51, + mainwin_volume_frame_cb, SKIN_VOLUME); + g_signal_connect(mainwin_volume, "motion", G_CALLBACK(mainwin_volume_motion_cb), NULL); + g_signal_connect(mainwin_volume, "release", G_CALLBACK(mainwin_volume_release_cb), NULL); + + mainwin_balance = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 177, 57, 38, + 13, 15, 422, 0, 422, 14, 11, 15, 9, 0, 24, + mainwin_balance_frame_cb, SKIN_BALANCE); + g_signal_connect(mainwin_balance, "motion", G_CALLBACK(mainwin_balance_motion_cb), NULL); + g_signal_connect(mainwin_balance, "release", G_CALLBACK(mainwin_balance_release_cb), NULL); + + mainwin_monostereo = ui_skinned_monostereo_new(SKINNED_WINDOW(mainwin)->fixed, 212, 41, SKIN_MONOSTEREO); + + mainwin_playstatus = ui_skinned_playstatus_new(SKINNED_WINDOW(mainwin)->fixed, 24, 28); + + mainwin_minus_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 36, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_minus_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_10min_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 48, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_10min_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_min_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 60, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_min_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_10sec_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 78, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_10sec_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_sec_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 90, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_sec_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_about = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_about, SKINNED_WINDOW(mainwin)->fixed, 247, 83, 20, 25); +#if 0 + g_signal_connect(mainwin_about, "clicked", show_about_window, NULL); +#endif + mainwin_vis = ui_vis_new(SKINNED_WINDOW(mainwin)->fixed, 24, 43, 76); + g_signal_connect(mainwin_vis, "button-press-event", G_CALLBACK(mainwin_vis_cb), NULL); + mainwin_svis = ui_svis_new(SKINNED_WINDOW(mainwin)->fixed, 79, 5); + g_signal_connect(mainwin_svis, "button-press-event", G_CALLBACK(mainwin_vis_cb), NULL); + + mainwin_position = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 16, 72, 248, + 10, 248, 0, 278, 0, 29, 10, 10, 0, 0, 219, + NULL, SKIN_POSBAR); + g_signal_connect(mainwin_position, "motion", G_CALLBACK(mainwin_position_motion_cb), NULL); + g_signal_connect(mainwin_position, "release", G_CALLBACK(mainwin_position_release_cb), NULL); + + mainwin_sposition = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 226, 4, 17, + 7, 17, 36, 17, 36, 3, 7, 36, 0, 1, 13, + mainwin_spos_frame_cb, SKIN_TITLEBAR); + g_signal_connect(mainwin_sposition, "motion", G_CALLBACK(mainwin_spos_motion_cb), NULL); + g_signal_connect(mainwin_sposition, "release", G_CALLBACK(mainwin_spos_release_cb), NULL); + + mainwin_stime_min = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 130, 4, 15, FALSE, SKIN_TEXT); + g_signal_connect(mainwin_stime_min, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_stime_sec = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 147, 4, 10, FALSE, SKIN_TEXT); + g_signal_connect(mainwin_stime_sec, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + + aud_hook_associate("playback audio error", (void *) mainwin_stop_pushed, NULL); + aud_hook_associate("playback audio error", (void *) run_no_output_device_dialog, NULL); + + aud_hook_associate("playback seek", (HookFunction) mainwin_update_song_info, NULL); +} + +static void +mainwin_create_window(void) +{ + gint width, height; + + mainwin = ui_skinned_window_new("player"); + gtk_window_set_title(GTK_WINDOW(mainwin), _("Audacious")); + gtk_window_set_role(GTK_WINDOW(mainwin), "player"); + gtk_window_set_resizable(GTK_WINDOW(mainwin), FALSE); + + width = config.player_shaded ? MAINWIN_SHADED_WIDTH : aud_active_skin->properties.mainwin_width; + height = config.player_shaded ? MAINWIN_SHADED_HEIGHT : aud_active_skin->properties.mainwin_height; + + if (config.scaled) { + width *= config.scale_factor; + height *= config.scale_factor; + } + + gtk_widget_set_size_request(mainwin, width, height); + + if (config.player_x != -1 && config.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), config.player_x, config.player_y); + + g_signal_connect(mainwin, "destroy", G_CALLBACK(mainwin_destroy), NULL); + g_signal_connect(mainwin, "button_press_event", + G_CALLBACK(mainwin_mouse_button_press), NULL); + g_signal_connect(mainwin, "scroll_event", + G_CALLBACK(mainwin_scrolled), NULL); + g_signal_connect(mainwin, "button_release_event", + G_CALLBACK(mainwin_mouse_button_release), NULL); + + aud_drag_dest_set(mainwin); + + g_signal_connect(mainwin, "key_press_event", + G_CALLBACK(mainwin_keypress), NULL); + + ui_main_evlistener_init(); +} + +void +mainwin_create(void) +{ + mainwin_create_window(); + + gtk_window_add_accel_group( GTK_WINDOW(mainwin) , ui_manager_get_accel_group() ); + + mainwin_create_widgets(); +} + +gboolean +mainwin_update_song_info(void) +{ + if (!audacious_drct_get_playing()) + return FALSE; + + gint time = audacious_drct_get_time(); + gint length = audacious_drct_get_length(); + gint t; + gchar stime_prefix; + + if (ab_position_a != -1 && ab_position_b != -1 && time > ab_position_b) + audacious_drct_seek(ab_position_a/1000); + + if (length == -1 && config.timer_mode == TIMER_REMAINING) + config.timer_mode = TIMER_ELAPSED; +#if 0 + playlistwin_set_time(time, length, config.timer_mode); +#endif + if (config.timer_mode == TIMER_REMAINING) { + if (length != -1) { + ui_skinned_number_set_number(mainwin_minus_num, 11); + t = length - time; + stime_prefix = '-'; + } + else { + ui_skinned_number_set_number(mainwin_minus_num, 10); + t = time; + stime_prefix = ' '; + } + } + else { + ui_skinned_number_set_number(mainwin_minus_num, 10); + t = time; + stime_prefix = ' '; + } + t /= 1000; + + /* Show the time in the format HH:MM when we have more than 100 + * minutes. */ + if (t >= 100 * 60) + t /= 60; + ui_skinned_number_set_number(mainwin_10min_num, t / 600); + ui_skinned_number_set_number(mainwin_min_num, (t / 60) % 10); + ui_skinned_number_set_number(mainwin_10sec_num, (t / 10) % 6); + ui_skinned_number_set_number(mainwin_sec_num, t % 10); + + if (!UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->pressed) { + gchar *time_str; + + time_str = g_strdup_printf("%c%2.2d", stime_prefix, t / 60); + ui_skinned_textbox_set_text(mainwin_stime_min, time_str); + g_free(time_str); + + time_str = g_strdup_printf("%2.2d", t % 60); + ui_skinned_textbox_set_text(mainwin_stime_sec, time_str); + g_free(time_str); + } + + time /= 1000; + length /= 1000; + if (length > 0) { + if (time > length) { + ui_skinned_horizontal_slider_set_position(mainwin_position, 219); + ui_skinned_horizontal_slider_set_position(mainwin_sposition, 13); + } + /* update the slider position ONLY if there is not a seek in progress */ + else if (seek_state == MAINWIN_SEEK_NIL) { + ui_skinned_horizontal_slider_set_position(mainwin_position, (time * 219) / length); + ui_skinned_horizontal_slider_set_position(mainwin_sposition, + ((time * 12) / length) + 1); + } + } + else { + ui_skinned_horizontal_slider_set_position(mainwin_position, 0); + ui_skinned_horizontal_slider_set_position(mainwin_sposition, 1); + } + + return TRUE; +} + +static gboolean +mainwin_idle_func(gpointer data) +{ + GDK_THREADS_ENTER(); + + /* tristate buttons seek */ + if ( seek_state != MAINWIN_SEEK_NIL ) + { + GTimeVal now_time; + GTimeVal delta_time; + gulong now_dur; + g_get_current_time(&now_time); + + delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; + delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; + + now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); + + if ( now_dur > TRISTATE_THRESHOLD ) + { + gint np; + if (seek_state == MAINWIN_SEEK_REV) + np = seek_initial_pos - labs((gulong)(now_dur/100)); /* seek back */ + else + np = seek_initial_pos + labs((gulong)(now_dur/100)); /* seek forward */ + + /* boundaries check */ + if (np < 0 ) + np = 0; + else if ( np > 219 ) + np = 219; + + ui_skinned_horizontal_slider_set_position( mainwin_position , np ); + mainwin_position_motion_cb( mainwin_position, np ); + } + } + + GDK_THREADS_LEAVE(); + return TRUE; +} + + +/* toggleactionentries actions */ + +void +action_anamode_peaks( GtkToggleAction * action ) +{ + config.analyzer_peaks = gtk_toggle_action_get_active( action ); +} + +void +action_autoscroll_songname( GtkToggleAction * action ) +{ + mainwin_set_title_scroll(gtk_toggle_action_get_active(action)); + playlistwin_set_sinfo_scroll(config.autoscroll); /* propagate scroll setting to playlistwin_sinfo */ +} + +void +action_playback_noplaylistadvance( GtkToggleAction * action ) +{ + aud_cfg->no_playlist_advance = gtk_toggle_action_get_active( action ); +} + +void +action_playback_repeat( GtkToggleAction * action ) +{ + aud_cfg->repeat = gtk_toggle_action_get_active( action ); + UI_SKINNED_BUTTON(mainwin_repeat)->inside = aud_cfg->repeat; + gtk_widget_queue_draw(mainwin_repeat); +} + +void +action_playback_shuffle( GtkToggleAction * action ) +{ + aud_cfg->shuffle = gtk_toggle_action_get_active( action ); + aud_playlist_set_shuffle(aud_cfg->shuffle); + UI_SKINNED_BUTTON(mainwin_shuffle)->inside = aud_cfg->shuffle; + gtk_widget_queue_draw(mainwin_shuffle); +} + +void +action_stop_after_current_song( GtkToggleAction * action ) +{ + aud_cfg->stopaftersong = gtk_toggle_action_get_active( action ); +} + +void +action_view_always_on_top( GtkToggleAction * action ) +{ + UI_SKINNED_MENUROW(mainwin_menurow)->always_selected = gtk_toggle_action_get_active( action ); + config.always_on_top = UI_SKINNED_MENUROW(mainwin_menurow)->always_selected; + gtk_widget_queue_draw(mainwin_menurow); + hint_set_always(config.always_on_top); +} + +void +action_view_scaled( GtkToggleAction * action ) +{ + UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected = gtk_toggle_action_get_active( action ); + gtk_widget_queue_draw(mainwin_menurow); + set_scaled(UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected); + gdk_flush(); +} + +void +action_view_easymove( GtkToggleAction * action ) +{ + config.easy_move = gtk_toggle_action_get_active( action ); +} + +void +action_view_on_all_workspaces( GtkToggleAction * action ) +{ + config.sticky = gtk_toggle_action_get_active( action ); + hint_set_sticky(config.sticky); +} + +void +action_roll_up_equalizer( GtkToggleAction * action ) +{ + equalizerwin_set_shade_menu_cb(gtk_toggle_action_get_active(action)); +} + +void +action_roll_up_player( GtkToggleAction * action ) +{ + mainwin_set_shade_menu_cb(gtk_toggle_action_get_active(action)); +} + +void +action_roll_up_playlist_editor( GtkToggleAction * action ) +{ + playlistwin_set_shade(gtk_toggle_action_get_active(action)); +} + +void +action_show_equalizer( GtkToggleAction * action ) +{ + if (gtk_toggle_action_get_active(action)) + equalizerwin_real_show(); + else + equalizerwin_real_hide(); +} + +void +action_show_playlist_editor( GtkToggleAction * action ) +{ + if (gtk_toggle_action_get_active(action)) + playlistwin_show(); + else + playlistwin_hide(); +} + +void +action_show_player( GtkToggleAction * action ) +{ + mainwin_show(gtk_toggle_action_get_active(action)); +} + + +/* radioactionentries actions (one callback for each radio group) */ + +void +action_anafoff( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_afalloff(gtk_radio_action_get_current_value(current)); +} + +void +action_anamode( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_analyzer_mode(gtk_radio_action_get_current_value(current)); +} + +void +action_anatype( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_analyzer_type(gtk_radio_action_get_current_value(current)); +} + +void +action_peafoff( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_pfalloff(gtk_radio_action_get_current_value(current)); +} + +void +action_refrate( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_refresh(gtk_radio_action_get_current_value(current)); +} + +void +action_scomode( GtkAction *action, GtkRadioAction *current ) +{ + config.scope_mode = gtk_radio_action_get_current_value(current); +} + +void +action_vismode( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_type_menu_cb(gtk_radio_action_get_current_value(current)); +} + +void +action_vprmode( GtkAction *action, GtkRadioAction *current ) +{ + config.voiceprint_mode = gtk_radio_action_get_current_value(current); +} + +void +action_wshmode( GtkAction *action, GtkRadioAction *current ) +{ + config.vu_mode = gtk_radio_action_get_current_value(current); +} + +void +action_viewtime( GtkAction *action, GtkRadioAction *current ) +{ + set_timer_mode_menu_cb(gtk_radio_action_get_current_value(current)); +} + + +/* actionentries actions */ + +void +action_about_audacious( void ) +{ +#if 0 + show_about_window(); +#endif +} + +void +action_play_file( void ) +{ + run_filebrowser(PLAY_BUTTON); +} + +void +action_play_location( void ) +{ + mainwin_show_add_url_window(); +} + +void +action_ab_set( void ) +{ + Playlist *playlist = aud_playlist_get_active(); + if (aud_playlist_get_current_length(playlist) != -1) + { + if (ab_position_a == -1) + { + ab_position_a = audacious_drct_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("LOOP-POINT A POSITION SET."); + } + else if (ab_position_b == -1) + { + int time = audacious_drct_get_time(); + if (time > ab_position_a) + ab_position_b = time; + mainwin_release_info_text(); + } + else + { + ab_position_a = audacious_drct_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("LOOP-POINT A POSITION RESET."); + } + } +} + +void +action_ab_clear( void ) +{ + Playlist *playlist = aud_playlist_get_active(); + if (aud_playlist_get_current_length(playlist) != -1) + { + ab_position_a = ab_position_b = -1; + mainwin_release_info_text(); + } +} + +void +action_current_track_info( void ) +{ +#if 0 + ui_fileinfo_show_current(aud_playlist_get_active()); +#endif +} + +void +action_jump_to_file( void ) +{ +#if 0 + ui_jump_to_track(); +#endif +} + +void +action_jump_to_playlist_start( void ) +{ + Playlist *playlist = aud_playlist_get_active(); + aud_playlist_set_position(playlist, 0); +} + +void +action_jump_to_time( void ) +{ + mainwin_jump_to_time(); +} + +void +action_playback_next( void ) +{ + Playlist *playlist = aud_playlist_get_active(); + aud_playlist_next(playlist); +} + +void +action_playback_previous( void ) +{ + Playlist *playlist = aud_playlist_get_active(); + aud_playlist_prev(playlist); +} + +void +action_playback_play( void ) +{ + mainwin_play_pushed(); +} + +void +action_playback_pause( void ) +{ + audacious_drct_pause(); +} + +void +action_playback_stop( void ) +{ + mainwin_stop_pushed(); +} + +void +action_preferences( void ) +{ +#if 0 + show_prefs_window(); +#endif +} + +void +action_quit( void ) +{ + mainwin_quit_cb(); +} + +void +util_menu_main_show( gint x , gint y , guint button , guint time ) +{ + /* convenience function that shows the main popup menu wherever requested */ + ui_manager_popup_menu_show( GTK_MENU(mainwin_general_menu), + x , y , button , time ); + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_main.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,194 @@ +/* BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_MAIN_H +#define AUDACIOUS_UI_MAIN_H + +#include <gtk/gtk.h> + +#include "ui_vis.h" +#include "ui_svis.h" + +/* yes, main window size is fixed */ +#define MAINWIN_WIDTH (gint)275 +#define MAINWIN_HEIGHT (gint)116 +#define MAINWIN_TITLEBAR_HEIGHT (gint)14 +#define MAINWIN_SHADED_WIDTH MAINWIN_WIDTH +#define MAINWIN_SHADED_HEIGHT MAINWIN_TITLEBAR_HEIGHT +#define MAINWIN_SCALE_FACTOR (config.scaled ? config.scale_factor : 1) + +#define MAINWIN_UPDATE_INTERVAL 100 + +#define MAINWIN_DEFAULT_POS_X 20 +#define MAINWIN_DEFAULT_POS_Y 20 + +#define MAINWIN_DEFAULT_FONT "Sans Bold 9" + + +typedef enum { + TIMER_ELAPSED, + TIMER_REMAINING +} TimerMode; + +enum { + MAINWIN_GENERAL_ABOUT, + + MAINWIN_GENERAL_PLAYFILE, + MAINWIN_GENERAL_PLAYLOCATION, + + MAINWIN_GENERAL_FILEINFO, + MAINWIN_GENERAL_PREFS, + + MAINWIN_GENERAL_SHOWMWIN, + MAINWIN_GENERAL_SHOWPLWIN, + + MAINWIN_GENERAL_FOCUSMWIN, + MAINWIN_GENERAL_FOCUSPLWIN, + + MAINWIN_GENERAL_SHOWEQWIN, + MAINWIN_GENERAL_EXIT, + + MAINWIN_GENERAL_PREV, + MAINWIN_GENERAL_PLAY, + MAINWIN_GENERAL_PAUSE, + MAINWIN_GENERAL_STOP, + MAINWIN_GENERAL_NEXT, + MAINWIN_GENERAL_STOPFADE, + MAINWIN_GENERAL_BACK5SEC, + MAINWIN_GENERAL_FWD5SEC, + MAINWIN_GENERAL_START, + MAINWIN_GENERAL_BACK10, + MAINWIN_GENERAL_FWD10, + MAINWIN_GENERAL_JTT, + MAINWIN_GENERAL_JTF, + MAINWIN_GENERAL_QUEUE, + MAINWIN_GENERAL_CQUEUE, + MAINWIN_GENERAL_VOLUP, + MAINWIN_GENERAL_VOLDOWN, + MAINWIN_GENERAL_SETAB, + MAINWIN_GENERAL_CLEARAB, + + MAINWIN_GENERAL_NEXT_PL, + MAINWIN_GENERAL_PREV_PL, + MAINWIN_GENERAL_NEW_PL +}; + +extern GtkWidget *mainwin; +extern GtkWidget *err; + +extern gboolean mainwin_moving; +extern gboolean mainwin_focus; + +extern GtkWidget *mainwin_jtf; +extern GtkWidget *mainwin_eq, *mainwin_pl; +extern GtkWidget *mainwin_info; + +extern GtkWidget *mainwin_stime_min, *mainwin_stime_sec; + +extern GtkWidget *mainwin_vis; +extern GtkWidget *mainwin_svis; + +extern GtkWidget *mainwin_playstatus; + +extern GtkWidget *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; +extern GtkWidget *mainwin_10sec_num, *mainwin_sec_num; + +extern GtkWidget *mainwin_position, *mainwin_sposition; + +void mainwin_create(void); +void ui_main_set_initial_volume(void); + +void mainwin_lock_info_text(const gchar * text); +void mainwin_release_info_text(void); +void mainwin_play_pushed(void); +void mainwin_stop_pushed(void); +void mainwin_eject_pushed(void); + +void mainwin_rev_pushed(void); +void mainwin_rev_release(void); +void mainwin_fwd_pushed(void); +void mainwin_fwd_release(void); + +void mainwin_adjust_volume_motion(gint v); +void mainwin_adjust_volume_release(void); +void mainwin_adjust_balance_motion(gint b); +void mainwin_adjust_balance_release(void); +void mainwin_set_volume_slider(gint percent); +void mainwin_set_balance_slider(gint percent); + +void mainwin_vis_set_type(VisType mode); + +void mainwin_refresh_hints(void); +void mainwin_set_info_text(void); +void mainwin_set_song_info(gint rate, gint freq, gint nch); +void mainwin_clear_song_info(void); +void mainwin_set_stopaftersong(gboolean stop); +void mainwin_set_noplaylistadvance(gboolean no_advance); + +void mainwin_set_always_on_top(gboolean always); +void mainwin_set_volume_diff(gint diff); +void mainwin_set_balance_diff(gint diff); + +void mainwin_show(gboolean); +void mainwin_real_show(void); +void mainwin_real_hide(void); +void mainwin_move(gint x, gint y); +void mainwin_shuffle_pushed(gboolean toggled); +void mainwin_repeat_pushed(gboolean toggled); +void mainwin_disable_seekbar(void); +void mainwin_set_title(const gchar * text); +void mainwin_show_add_url_window(void); +void mainwin_minimize_cb(void); +void mainwin_general_menu_callback(gpointer cb_data, + guint action, + GtkWidget * widget); + +gboolean mainwin_update_song_info(void); +void mainwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, + gint y, + GtkSelectionData * selection_data, + guint info, + guint time, + gpointer user_data); + +void mainwin_setup_menus(void); +gboolean change_timer_mode_cb(GtkWidget *widget, GdkEventButton *event); + +void mainwin_jump_to_file(void); +void mainwin_jump_to_time(void); + +void mainwin_ewmh_activate(void); + +void mainwin_show_visibility_warning(void); + +/* FIXME: placed here for now */ +void playback_get_sample_params(gint * bitrate, + gint * frequency, + gint * numchannels); + +void ui_main_check_theme_engine(void); + +void util_menu_main_show( gint x , gint y , guint button , guint time ); + +#endif /* AUDACIOUS_UI_MAIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_main_evlisteners.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,336 @@ +/* + * Audacious + * Copyright (c) 2006-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ +#if 0 +#include "ui_playlist_evlisteners.h" +#endif +#include <glib.h> +#include <math.h> +#if 0 +#include "hook.h" +#include "playback.h" +#include "playlist.h" +#include "playlist_evmessages.h" +#include "visualization.h" +#endif +#include <audacious/plugin.h> +#if 0 +#include "ui_credits.h" +#include "ui_equalizer.h" +#include "ui_jumptotrack.h" +#endif +#include "ui_fileopener.h" +#include "ui_main.h" +#if 0 +#include "ui_playlist.h" +#include "ui_preferences.h" +#endif +#include "ui_skinned_playstatus.h" +#include "ui_skinned_textbox.h" +#include "ui_skinned_window.h" +#include "skins_cfg.h" + +static gint song_info_timeout_source = 0; +static gint update_vis_timeout_source = 0; + +typedef struct { + gint bitrate; + gint samplerate; + gint channels; +} PlaylistEventInfoChange; + +/* XXX: there has to be a better way than polling here! */ +/* also: where should this function go? should it stay here? --mf0102 */ +static gboolean +update_vis_func(gpointer unused) +{ + if (!audacious_drct_get_playing()) + return FALSE; +#if 0 + input_update_vis(audacious_drct_get_time()); +#endif + return TRUE; +} + +static void +ui_main_evlistener_title_change(gpointer hook_data, gpointer user_data) +{ + gchar *text = (gchar *) hook_data; + + ui_skinned_textbox_set_text(mainwin_info, text); + playlistwin_update_list(aud_playlist_get_active()); +} + +static void +ui_main_evlistener_hide_seekbar(gpointer hook_data, gpointer user_data) +{ + mainwin_disable_seekbar(); +} + +static void +ui_main_evlistener_volume_change(gpointer hook_data, gpointer user_data) +{ + gint *h_vol = (gint *) hook_data; + gint vl, vr, b, v; + + vl = CLAMP(h_vol[0], 0, 100); + vr = CLAMP(h_vol[1], 0, 100); + v = MAX(vl, vr); + if (vl > vr) + b = (gint) rint(((gdouble) vr / vl) * 100) - 100; + else if (vl < vr) + b = 100 - (gint) rint(((gdouble) vl / vr) * 100); + else + b = 0; + + mainwin_set_volume_slider(v); + equalizerwin_set_volume_slider(v); + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); +} + +static void +ui_main_evlistener_playback_begin(gpointer hook_data, gpointer user_data) +{ + + PlaylistEntry *entry = (PlaylistEntry*)hook_data; + g_return_if_fail(entry != NULL); +#if 0 + equalizerwin_load_auto_preset(entry->filename); + input_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, + cfg.equalizer_bands); + output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, + cfg.equalizer_bands); +#endif + ui_vis_clear_data(mainwin_vis); + ui_svis_clear_data(mainwin_svis); + mainwin_disable_seekbar(); + mainwin_update_song_info(); + + if (config.player_shaded) { + gtk_widget_show(mainwin_stime_min); + gtk_widget_show(mainwin_stime_sec); + gtk_widget_show(mainwin_sposition); + } else { + gtk_widget_show(mainwin_minus_num); + gtk_widget_show(mainwin_10min_num); + gtk_widget_show(mainwin_min_num); + gtk_widget_show(mainwin_10sec_num); + gtk_widget_show(mainwin_sec_num); + gtk_widget_show(mainwin_position); + } + + song_info_timeout_source = + g_timeout_add_seconds(1, (GSourceFunc) mainwin_update_song_info, NULL); + + update_vis_timeout_source = + g_timeout_add(10, (GSourceFunc) update_vis_func, NULL); +#if 0 + vis_playback_start(); +#endif + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); +} + +static void +ui_main_evlistener_playback_stop(gpointer hook_data, gpointer user_data) +{ + if (song_info_timeout_source) + g_source_remove(song_info_timeout_source); +#if 0 + vis_playback_stop(); + free_vis_data(); +#endif + ui_skinned_playstatus_set_buffering(mainwin_playstatus, FALSE); +} + +static void +ui_main_evlistener_playback_pause(gpointer hook_data, gpointer user_data) +{ + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PAUSE); +} + +static void +ui_main_evlistener_playback_unpause(gpointer hook_data, gpointer user_data) +{ + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); +} + +static void +ui_main_evlistener_playback_seek(gpointer hook_data, gpointer user_data) +{ +#if 0 + free_vis_data(); +#endif +} + +static void +ui_main_evlistener_playback_play_file(gpointer hook_data, gpointer user_data) +{ +#if 0 + if (cfg.random_skin_on_play) + skin_set_random_skin(); +#endif +} + +static void +ui_main_evlistener_playlist_end_reached(gpointer hook_data, gpointer user_data) +{ + mainwin_clear_song_info(); +#if 0 + if (cfg.stopaftersong) + mainwin_set_stopaftersong(FALSE); +#endif +} + +static void +ui_main_evlistener_playlist_info_change(gpointer hook_data, gpointer user_data) +{ + PlaylistEventInfoChange *msg = (PlaylistEventInfoChange *) hook_data; + + mainwin_set_song_info(msg->bitrate, msg->samplerate, msg->channels); +} + +static void +ui_main_evlistener_mainwin_set_always_on_top(gpointer hook_data, gpointer user_data) +{ + gboolean *ontop = (gboolean*)hook_data; + mainwin_set_always_on_top(*ontop); +} + +static void +ui_main_evlistener_mainwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + mainwin_show(*show); +} + +static void +ui_main_evlistener_equalizerwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + equalizerwin_show(*show); +} + +static void +ui_main_evlistener_prefswin_show(gpointer hook_data, gpointer user_data) +{ +#if 0 + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + show_prefs_window(); + else + hide_prefs_window(); +#endif +} + +static void +ui_main_evlistener_aboutwin_show(gpointer hook_data, gpointer user_data) +{ +#if 0 + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + show_about_window(); + else + hide_about_window(); +#endif +} + + +static void +ui_main_evlistener_ui_jump_to_track_show(gpointer hook_data, gpointer user_data) +{ +#if 0 + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + ui_jump_to_track(); + else + ui_jump_to_track_hide(); +#endif +} + +static void +ui_main_evlistener_filebrowser_show(gpointer hook_data, gpointer user_data) +{ +#if 0 + gboolean *play_button = (gboolean*)hook_data; + run_filebrowser(*play_button); +#endif +} + +static void +ui_main_evlistener_filebrowser_hide(gpointer hook_data, gpointer user_data) +{ +#if 0 + hide_filebrowser(); +#endif +} + +static void +ui_main_evlistener_visualization_timeout(gpointer hook_data, gpointer user_data) +{ + if (config.player_shaded && config.player_visible) + ui_svis_timeout_func(mainwin_svis, hook_data); + else + ui_vis_timeout_func(mainwin_vis, hook_data); +} + +static void +ui_main_evlistener_config_save(gpointer hook_data, gpointer user_data) +{ + ConfigDb *db = (ConfigDb *) hook_data; + + if (SKINNED_WINDOW(mainwin)->x != -1 && + SKINNED_WINDOW(mainwin)->y != -1 ) + { + aud_cfg_db_set_int(db, "skins", "player_x", SKINNED_WINDOW(mainwin)->x); + aud_cfg_db_set_int(db, "skins", "player_y", SKINNED_WINDOW(mainwin)->y); + } + + aud_cfg_db_set_bool(db, "skins", "mainwin_use_bitmapfont", + config.mainwin_use_bitmapfont); +} + +void +ui_main_evlistener_init(void) +{ + aud_hook_associate("title change", ui_main_evlistener_title_change, NULL); + aud_hook_associate("hide seekbar", ui_main_evlistener_hide_seekbar, NULL); + aud_hook_associate("volume set", ui_main_evlistener_volume_change, NULL); + aud_hook_associate("playback begin", ui_main_evlistener_playback_begin, NULL); + aud_hook_associate("playback stop", ui_main_evlistener_playback_stop, NULL); + aud_hook_associate("playback pause", ui_main_evlistener_playback_pause, NULL); + aud_hook_associate("playback unpause", ui_main_evlistener_playback_unpause, NULL); + aud_hook_associate("playback seek", ui_main_evlistener_playback_seek, NULL); + aud_hook_associate("playback play file", ui_main_evlistener_playback_play_file, NULL); + aud_hook_associate("playlist end reached", ui_main_evlistener_playlist_end_reached, NULL); + aud_hook_associate("playlist info change", ui_main_evlistener_playlist_info_change, NULL); + aud_hook_associate("mainwin set always on top", ui_main_evlistener_mainwin_set_always_on_top, NULL); + aud_hook_associate("mainwin show", ui_main_evlistener_mainwin_show, NULL); + aud_hook_associate("equalizerwin show", ui_main_evlistener_equalizerwin_show, NULL); +#if 0 + aud_hook_associate("prefswin show", ui_main_evlistener_prefswin_show, NULL); + aud_hook_associate("aboutwin show", ui_main_evlistener_aboutwin_show, NULL); + aud_hook_associate("ui jump to track show", ui_main_evlistener_ui_jump_to_track_show, NULL); + aud_hook_associate("filebrowser show", ui_main_evlistener_filebrowser_show, NULL); + aud_hook_associate("filebrowser hide", ui_main_evlistener_filebrowser_hide, NULL); +#endif + aud_hook_associate("visualization timeout", ui_main_evlistener_visualization_timeout, NULL); + aud_hook_associate("config save", ui_main_evlistener_config_save, NULL); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_main_evlisteners.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,28 @@ +/* + * Audacious + * Copyright (c) 2006-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include <glib.h> + +#ifndef AUDACIOUS_UI_MAIN_EVLISTENERS_H +#define AUDACIOUS_UI_MAIN_EVLISTENERS_H + +void ui_main_evlistener_init(void); + +#endif /* AUDACIOUS_UI_MAIN_EVLISTENERS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_manager.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,877 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui_manager.h" +#include "actions-mainwin.h" +#include "actions-playlist.h" +#include "actions-equalizer.h" + +#if 0 +/* this header contains prototypes for plugin-available menu functions */ +#include "ui_plugin_menu.h" +#endif + +/* TODO ui_main.h is only included because ui_manager.c needs the values of + TimerMode enum; move that enum elsewhere so we can get rid of this include */ +#include "ui_main.h" + +#include "icons-stock.h" +#if 0 +#include "sync-menu.h" +#endif +#include "plugin.h" +#include <audacious/ui_plugin_menu.h> + +static GtkUIManager *ui_manager = NULL; +static gboolean menu_created = FALSE; + + +/* toggle action entries */ + +static GtkToggleActionEntry toggleaction_entries_others[] = { + + { "autoscroll songname", NULL , N_("Autoscroll Songname"), NULL, + N_("Autoscroll Songname"), G_CALLBACK(action_autoscroll_songname) , FALSE }, + + { "stop after current song", NULL , N_("Stop after Current Song"), "<Ctrl>M", + N_("Stop after Current Song"), G_CALLBACK(action_stop_after_current_song) , FALSE }, + + { "anamode peaks", NULL , N_("Peaks"), NULL, + N_("Peaks"), G_CALLBACK(action_anamode_peaks) , FALSE }, + + { "playback repeat", NULL , N_("Repeat"), "R", + N_("Repeat"), G_CALLBACK(action_playback_repeat) , FALSE }, + + { "playback shuffle", NULL , N_("Shuffle"), "S", + N_("Shuffle"), G_CALLBACK(action_playback_shuffle) , FALSE }, + + { "playback no playlist advance", NULL , N_("No Playlist Advance"), "<Ctrl>N", + N_("No Playlist Advance"), G_CALLBACK(action_playback_noplaylistadvance) , FALSE }, + + { "show player", NULL , N_("Show Player"), "<Alt>M", + N_("Show Player"), G_CALLBACK(action_show_player) , FALSE }, + + { "show playlist editor", NULL , N_("Show Playlist Editor"), "<Alt>E", + N_("Show Playlist Editor"), G_CALLBACK(action_show_playlist_editor) , FALSE }, + + { "show equalizer", NULL , N_("Show Equalizer"), "<Alt>G", + N_("Show Equalizer"), G_CALLBACK(action_show_equalizer) , FALSE }, + + { "view always on top", NULL , N_("Always on Top"), "<Ctrl>O", + N_("Always on Top"), G_CALLBACK(action_view_always_on_top) , FALSE }, + + { "view put on all workspaces", NULL , N_("Put on All Workspaces"), "<Ctrl>S", + N_("Put on All Workspaces"), G_CALLBACK(action_view_on_all_workspaces) , FALSE }, + + { "roll up player", NULL , N_("Roll up Player"), "<Ctrl>W", + N_("Roll up Player"), G_CALLBACK(action_roll_up_player) , FALSE }, + + { "roll up playlist editor", NULL , N_("Roll up Playlist Editor"), "<Shift><Ctrl>W", + N_("Roll up Playlist Editor"), G_CALLBACK(action_roll_up_playlist_editor) , FALSE }, + + { "roll up equalizer", NULL , N_("Roll up Equalizer"), "<Ctrl><Alt>W", + N_("Roll up Equalizer"), G_CALLBACK(action_roll_up_equalizer) , FALSE }, + + { "view scaled", NULL , N_("Scale"), "<Ctrl>D", + N_("DoubleSize"), G_CALLBACK(action_view_scaled) , FALSE }, + + { "view easy move", NULL , N_("Easy Move"), "<Ctrl>E", + N_("Easy Move"), G_CALLBACK(action_view_easymove) , FALSE } +}; + + + +/* radio action entries */ + +static GtkRadioActionEntry radioaction_entries_vismode[] = { + { "vismode analyzer", NULL , N_("Analyzer"), NULL, N_("Analyzer"), VIS_ANALYZER }, + { "vismode scope", NULL , N_("Scope"), NULL, N_("Scope"), VIS_SCOPE }, + { "vismode voiceprint", NULL , N_("Voiceprint"), NULL, N_("Voiceprint"), VIS_VOICEPRINT }, + { "vismode off", NULL , N_("Off"), NULL, N_("Off"), VIS_OFF } +}; + +static GtkRadioActionEntry radioaction_entries_anamode[] = { + { "anamode normal", NULL , N_("Normal"), NULL, N_("Normal"), ANALYZER_NORMAL }, + { "anamode fire", NULL , N_("Fire"), NULL, N_("Fire"), ANALYZER_FIRE }, + { "anamode vertical lines", NULL , N_("Vertical Lines"), NULL, N_("Vertical Lines"), ANALYZER_VLINES } +}; + +static GtkRadioActionEntry radioaction_entries_anatype[] = { + { "anatype lines", NULL , N_("Lines"), NULL, N_("Lines"), ANALYZER_LINES }, + { "anatype bars", NULL , N_("Bars"), NULL, N_("Bars"), ANALYZER_BARS } +}; + +static GtkRadioActionEntry radioaction_entries_scomode[] = { + { "scomode dot", NULL , N_("Dot Scope"), NULL, N_("Dot Scope"), SCOPE_DOT }, + { "scomode line", NULL , N_("Line Scope"), NULL, N_("Line Scope"), SCOPE_LINE }, + { "scomode solid", NULL , N_("Solid Scope"), NULL, N_("Solid Scope"), SCOPE_SOLID } +}; + +static GtkRadioActionEntry radioaction_entries_vprmode[] = { + { "vprmode normal", NULL , N_("Normal"), NULL, N_("Normal"), VOICEPRINT_NORMAL }, + { "vprmode fire", NULL , N_("Fire"), NULL, N_("Fire"), VOICEPRINT_FIRE }, + { "vprmode ice", NULL , N_("Ice"), NULL, N_("Ice"), VOICEPRINT_ICE } +}; + +static GtkRadioActionEntry radioaction_entries_wshmode[] = { + { "wshmode normal", NULL , N_("Normal"), NULL, N_("Normal"), VU_NORMAL }, + { "wshmode smooth", NULL , N_("Smooth"), NULL, N_("Smooth"), VU_SMOOTH } +}; + +static GtkRadioActionEntry radioaction_entries_refrate[] = { + { "refrate full", NULL , N_("Full (~50 fps)"), NULL, N_("Full (~50 fps)"), REFRESH_FULL }, + { "refrate half", NULL , N_("Half (~25 fps)"), NULL, N_("Half (~25 fps)"), REFRESH_HALF }, + { "refrate quarter", NULL , N_("Quarter (~13 fps)"), NULL, N_("Quarter (~13 fps)"), REFRESH_QUARTER }, + { "refrate eighth", NULL , N_("Eighth (~6 fps)"), NULL, N_("Eighth (~6 fps)"), REFRESH_EIGTH } +}; + +static GtkRadioActionEntry radioaction_entries_anafoff[] = { + { "anafoff slowest", NULL , N_("Slowest"), NULL, N_("Slowest"), FALLOFF_SLOWEST }, + { "anafoff slow", NULL , N_("Slow"), NULL, N_("Slow"), FALLOFF_SLOW }, + { "anafoff medium", NULL , N_("Medium"), NULL, N_("Medium"), FALLOFF_MEDIUM }, + { "anafoff fast", NULL , N_("Fast"), NULL, N_("Fast"), FALLOFF_FAST }, + { "anafoff fastest", NULL , N_("Fastest"), NULL, N_("Fastest"), FALLOFF_FASTEST } +}; + +static GtkRadioActionEntry radioaction_entries_peafoff[] = { + { "peafoff slowest", NULL , N_("Slowest"), NULL, N_("Slowest"), FALLOFF_SLOWEST }, + { "peafoff slow", NULL , N_("Slow"), NULL, N_("Slow"), FALLOFF_SLOW }, + { "peafoff medium", NULL , N_("Medium"), NULL, N_("Medium"), FALLOFF_MEDIUM }, + { "peafoff fast", NULL , N_("Fast"), NULL, N_("Fast"), FALLOFF_FAST }, + { "peafoff fastest", NULL , N_("Fastest"), NULL, N_("Fastest"), FALLOFF_FASTEST } +}; + +static GtkRadioActionEntry radioaction_entries_viewtime[] = { + { "view time elapsed", NULL , N_("Time Elapsed"), "<Ctrl>E", N_("Time Elapsed"), TIMER_ELAPSED }, + { "view time remaining", NULL , N_("Time Remaining"), "<Ctrl>R", N_("Time Remaining"), TIMER_REMAINING } +}; + + + +/* normal actions */ + +static GtkActionEntry action_entries_playback[] = { + + { "playback", NULL, N_("Playback") }, + + { "playback play", GTK_STOCK_MEDIA_PLAY , N_("Play"), "X", + N_("Play"), G_CALLBACK(action_playback_play) }, + + { "playback pause", GTK_STOCK_MEDIA_PAUSE , N_("Pause"), "C", + N_("Pause"), G_CALLBACK(action_playback_pause) }, + + { "playback stop", GTK_STOCK_MEDIA_STOP , N_("Stop"), "V", + N_("Stop"), G_CALLBACK(action_playback_stop) }, + + { "playback previous", GTK_STOCK_MEDIA_PREVIOUS , N_("Previous"), "Z", + N_("Previous"), G_CALLBACK(action_playback_previous) }, + + { "playback next", GTK_STOCK_MEDIA_NEXT , N_("Next"), "B", + N_("Next"), G_CALLBACK(action_playback_next) } +}; + + +static GtkActionEntry action_entries_visualization[] = { + { "visualization", NULL, N_("Visualization") }, + { "vismode", NULL, N_("Visualization Mode") }, + { "anamode", NULL, N_("Analyzer Mode") }, + { "scomode", NULL, N_("Scope Mode") }, + { "vprmode", NULL, N_("Voiceprint Mode") }, + { "wshmode", NULL, N_("WindowShade VU Mode") }, + { "refrate", NULL, N_("Refresh Rate") }, + { "anafoff", NULL, N_("Analyzer Falloff") }, + { "peafoff", NULL, N_("Peaks Falloff") } +}; + +static GtkActionEntry action_entries_playlist[] = { + + { "playlist", NULL, N_("Playlist") }, + + { "playlist new", GTK_STOCK_NEW , N_("New Playlist"), "<Shift>N", + N_("New Playlist"), G_CALLBACK(action_playlist_new) }, + + { "playlist select next", GTK_STOCK_MEDIA_NEXT, N_("Select Next Playlist"), "<Shift>P", + N_("Select Next Playlist"), G_CALLBACK(action_playlist_next) }, + + { "playlist select previous", GTK_STOCK_MEDIA_PREVIOUS, N_("Select Previous Playlist"), "<Shift><Ctrl>P", + N_("Select Previous Playlist"), G_CALLBACK(action_playlist_prev) }, + + { "playlist delete", GTK_STOCK_DELETE , N_("Delete Playlist"), "<Shift>D", + N_("Delete Playlist"), G_CALLBACK(action_playlist_delete) }, + + { "playlist load", GTK_STOCK_OPEN, N_("Load List"), "O", + N_("Loads a playlist file into the selected playlist."), G_CALLBACK(action_playlist_load_list) }, + + { "playlist save", GTK_STOCK_SAVE, N_("Save List"), "<Shift>S", + N_("Saves the selected playlist."), G_CALLBACK(action_playlist_save_list) }, + + { "playlist save default", GTK_STOCK_SAVE, N_("Save Default List"), "<Alt>S", + N_("Saves the selected playlist to the default location."), + G_CALLBACK(action_playlist_save_default_list) }, + + { "playlist refresh", GTK_STOCK_REFRESH, N_("Refresh List"), "F5", + N_("Refreshes metadata associated with a playlist entry."), + G_CALLBACK(action_playlist_refresh_list) }, + + { "playlist manager", AUD_STOCK_PLAYLIST , N_("List Manager"), "P", + N_("Opens the playlist manager."), + G_CALLBACK(action_open_list_manager) } +}; + +static GtkActionEntry action_entries_view[] = { + + { "view", NULL, N_("View") } +}; + +static GtkActionEntry action_entries_playlist_add[] = { + { "playlist add url", GTK_STOCK_NETWORK, N_("Add Internet Address..."), "<Ctrl>H", + N_("Adds a remote track to the playlist."), + G_CALLBACK(action_playlist_add_url) }, + + { "playlist add files", GTK_STOCK_ADD, N_("Add Files..."), "F", + N_("Adds files to the playlist."), + G_CALLBACK(action_playlist_add_files) }, +}; + +static GtkActionEntry action_entries_playlist_select[] = { + { "playlist search and select", GTK_STOCK_FIND, N_("Search and Select"), "<Ctrl>F", + N_("Searches the playlist and selects playlist entries based on specific criteria."), + G_CALLBACK(action_playlist_search_and_select) }, + + { "playlist invert selection", NULL , N_("Invert Selection"), NULL, + N_("Inverts the selected and unselected entries."), + G_CALLBACK(action_playlist_invert_selection) }, + + { "playlist select all", NULL , N_("Select All"), "<Ctrl>A", + N_("Selects all of the playlist entries."), + G_CALLBACK(action_playlist_select_all) }, + + { "playlist select none", NULL , N_("Select None"), "<Shift><Ctrl>A", + N_("Deselects all of the playlist entries."), + G_CALLBACK(action_playlist_select_none) }, +}; + +static GtkActionEntry action_entries_playlist_delete[] = { + { "playlist remove all", GTK_STOCK_CLEAR, N_("Remove All"), NULL, + N_("Removes all entries from the playlist."), + G_CALLBACK(action_playlist_remove_all) }, + + { "playlist clear queue", GTK_STOCK_CLEAR, N_("Clear Queue"), "<Shift>Q", + N_("Clears the queue associated with this playlist."), + G_CALLBACK(action_playlist_clear_queue) }, + + { "playlist remove unavailable", GTK_STOCK_DIALOG_ERROR , N_("Remove Unavailable Files"), NULL, + N_("Removes unavailable files from the playlist."), + G_CALLBACK(action_playlist_remove_unavailable) }, + + { "playlist remove dups menu", NULL , N_("Remove Duplicates") }, + + { "playlist remove dups by title", NULL , N_("By Title"), NULL, + N_("Removes duplicate entries from the playlist by title."), + G_CALLBACK(action_playlist_remove_dupes_by_title) }, + + { "playlist remove dups by filename", NULL , N_("By Filename"), NULL, + N_("Removes duplicate entries from the playlist by filename."), + G_CALLBACK(action_playlist_remove_dupes_by_filename) }, + + { "playlist remove dups by full path", NULL , N_("By Path + Filename"), NULL, + N_("Removes duplicate entries from the playlist by their full path."), + G_CALLBACK(action_playlist_remove_dupes_by_full_path) }, + + { "playlist remove unselected", GTK_STOCK_REMOVE, N_("Remove Unselected"), NULL, + N_("Remove unselected entries from the playlist."), + G_CALLBACK(action_playlist_remove_unselected) }, + + { "playlist remove selected", GTK_STOCK_REMOVE, N_("Remove Selected"), "Delete", + N_("Remove selected entries from the playlist."), + G_CALLBACK(action_playlist_remove_selected) }, +}; + +static GtkActionEntry action_entries_playlist_sort[] = { + { "playlist randomize list", AUD_STOCK_RANDOMIZEPL , N_("Randomize List"), "<Ctrl><Shift>R", + N_("Randomizes the playlist."), + G_CALLBACK(action_playlist_randomize_list) }, + + { "playlist reverse list", GTK_STOCK_GO_UP , N_("Reverse List"), NULL, + N_("Reverses the playlist."), + G_CALLBACK(action_playlist_reverse_list) }, + + { "playlist sort menu", GTK_STOCK_GO_DOWN , N_("Sort List") }, + + { "playlist sort by title", NULL , N_("By Title"), NULL, + N_("Sorts the list by title."), + G_CALLBACK(action_playlist_sort_by_title) }, + + { "playlist sort by artist", NULL , N_("By Artist"), NULL, + N_("Sorts the list by artist."), + G_CALLBACK(action_playlist_sort_by_artist) }, + + { "playlist sort by filename", NULL , N_("By Filename"), NULL, + N_("Sorts the list by filename."), + G_CALLBACK(action_playlist_sort_by_filename) }, + + { "playlist sort by full path", NULL , N_("By Path + Filename"), NULL, + N_("Sorts the list by full pathname."), + G_CALLBACK(action_playlist_sort_by_full_path) }, + + { "playlist sort by date", NULL , N_("By Date"), NULL, + N_("Sorts the list by modification time."), + G_CALLBACK(action_playlist_sort_by_date) }, + + { "playlist sort by track number", NULL , N_("By Track Number"), NULL, + N_("Sorts the list by track number."), + G_CALLBACK(action_playlist_sort_by_track_number) }, + + { "playlist sort by playlist entry", NULL , N_("By Playlist Entry"), NULL, + N_("Sorts the list by playlist entry."), + G_CALLBACK(action_playlist_sort_by_playlist_entry) }, + + { "playlist sort selected menu", GTK_STOCK_GO_DOWN , N_("Sort Selected") }, + + { "playlist sort selected by title", NULL , N_("By Title"), NULL, + N_("Sorts the list by title."), + G_CALLBACK(action_playlist_sort_selected_by_title) }, + + { "playlist sort selected by artist", NULL, N_("By Artist"), NULL, + N_("Sorts the list by artist."), + G_CALLBACK(action_playlist_sort_selected_by_artist) }, + + { "playlist sort selected by filename", NULL , N_("By Filename"), NULL, + N_("Sorts the list by filename."), + G_CALLBACK(action_playlist_sort_selected_by_filename) }, + + { "playlist sort selected by full path", NULL , N_("By Path + Filename"), NULL, + N_("Sorts the list by full pathname."), + G_CALLBACK(action_playlist_sort_selected_by_full_path) }, + + { "playlist sort selected by date", NULL , N_("By Date"), NULL, + N_("Sorts the list by modification time."), + G_CALLBACK(action_playlist_sort_selected_by_date) }, + + { "playlist sort selected by track number", NULL , N_("By Track Number"), NULL, + N_("Sorts the list by track number."), + G_CALLBACK(action_playlist_sort_selected_by_track_number) }, + + { "playlist sort selected by playlist entry", NULL, N_("By Playlist Entry"), NULL, + N_("Sorts the list by playlist entry."), + G_CALLBACK(action_playlist_sort_selected_by_playlist_entry) }, +}; + +static GtkActionEntry action_entries_others[] = { + + { "dummy", NULL, "dummy" }, + + /* XXX Carbon support */ + { "file", NULL, N_("File") }, + { "help", NULL, N_("Help") }, + + { "plugins-menu", AUD_STOCK_PLUGIN, N_("Plugin Services") }, + + { "current track info", GTK_STOCK_INFO , N_("View Track Details"), "I", + N_("View track details"), G_CALLBACK(action_current_track_info) }, + + { "playlist track info", GTK_STOCK_INFO , N_("View Track Details"), "<Alt>I", + N_("View track details"), G_CALLBACK(action_playlist_track_info) }, + + { "about audacious", GTK_STOCK_DIALOG_INFO , N_("About Audacious"), NULL, + N_("About Audacious"), G_CALLBACK(action_about_audacious) }, + + { "play file", GTK_STOCK_OPEN , N_("Play File"), "L", + N_("Load and play a file"), G_CALLBACK(action_play_file) }, + + { "play location", GTK_STOCK_NETWORK , N_("Play Location"), "<Ctrl>L", + N_("Play media from the selected location"), G_CALLBACK(action_play_location) }, + + { "plugins", NULL , N_("Plugin services") }, + + { "preferences", GTK_STOCK_PREFERENCES , N_("Preferences"), "<Ctrl>P", + N_("Open preferences window"), G_CALLBACK(action_preferences) }, + + { "quit", GTK_STOCK_QUIT , N_("_Quit"), NULL, + N_("Quit Audacious"), G_CALLBACK(action_quit) }, + + { "ab set", NULL , N_("Set A-B"), "A", + N_("Set A-B"), G_CALLBACK(action_ab_set) }, + + { "ab clear", NULL , N_("Clear A-B"), "<Shift>A", + N_("Clear A-B"), G_CALLBACK(action_ab_clear) }, + + { "jump to playlist start", GTK_STOCK_GOTO_TOP , N_("Jump to Playlist Start"), "<Ctrl>Z", + N_("Jump to Playlist Start"), G_CALLBACK(action_jump_to_playlist_start) }, + + { "jump to file", GTK_STOCK_JUMP_TO , N_("Jump to File"), "J", + N_("Jump to File"), G_CALLBACK(action_jump_to_file) }, + + { "jump to time", GTK_STOCK_JUMP_TO , N_("Jump to Time"), "<Ctrl>J", + N_("Jump to Time"), G_CALLBACK(action_jump_to_time) }, + + { "queue toggle", AUD_STOCK_QUEUETOGGLE , N_("Queue Toggle"), "Q", + N_("Enables/disables the entry in the playlist's queue."), + G_CALLBACK(action_queue_toggle) }, +}; + + +static GtkActionEntry action_entries_equalizer[] = { + + { "equ preset load menu", NULL, N_("Load") }, + { "equ preset import menu", NULL, N_("Import") }, + { "equ preset save menu", NULL, N_("Save") }, + { "equ preset delete menu", NULL, N_("Delete") }, + + { "equ load preset", NULL, N_("Preset"), NULL, + N_("Load preset"), G_CALLBACK(action_equ_load_preset) }, + + { "equ load auto preset", NULL, N_("Auto-load preset"), NULL, + N_("Load auto-load preset"), G_CALLBACK(action_equ_load_auto_preset) }, + + { "equ load default preset", NULL, N_("Default"), NULL, + N_("Load default preset into equalizer"), G_CALLBACK(action_equ_load_default_preset) }, + + { "equ zero preset", NULL, N_("Zero"), NULL, + N_("Set equalizer preset levels to zero"), G_CALLBACK(action_equ_zero_preset) }, + + { "equ load preset file", NULL, N_("From file"), NULL, + N_("Load preset from file"), G_CALLBACK(action_equ_load_preset_file) }, + + { "equ load preset eqf", NULL, N_("From WinAMP EQF file"), NULL, + N_("Load preset from WinAMP EQF file"), G_CALLBACK(action_equ_load_preset_eqf) }, + + { "equ import winamp presets", NULL, N_("WinAMP Presets"), NULL, + N_("Import WinAMP presets"), G_CALLBACK(action_equ_import_winamp_presets) }, + + { "equ save preset", NULL, N_("Preset"), NULL, + N_("Save preset"), G_CALLBACK(action_equ_save_preset) }, + + { "equ save auto preset", NULL, N_("Auto-load preset"), NULL, + N_("Save auto-load preset"), G_CALLBACK(action_equ_save_auto_preset) }, + + { "equ save default preset", NULL, N_("Default"), NULL, + N_("Save default preset"), G_CALLBACK(action_equ_save_default_preset) }, + + { "equ save preset file", NULL, N_("To file"), NULL, + N_("Save preset to file"), G_CALLBACK(action_equ_save_preset_file) }, + + { "equ save preset eqf", NULL, N_("To WinAMP EQF file"), NULL, + N_("Save preset to WinAMP EQF file"), G_CALLBACK(action_equ_save_preset_eqf) }, + + { "equ delete preset", NULL, N_("Preset"), NULL, + N_("Delete preset"), G_CALLBACK(action_equ_delete_preset) }, + + { "equ delete auto preset", NULL, N_("Auto-load preset"), NULL, + N_("Delete auto-load preset"), G_CALLBACK(action_equ_delete_auto_preset) } +}; + + + +/* ***************************** */ + + +static GtkActionGroup * +ui_manager_new_action_group( const gchar * group_name ) +{ + GtkActionGroup *group = gtk_action_group_new( group_name ); + gtk_action_group_set_translation_domain( group , PACKAGE_NAME ); + return group; +} + +void +ui_manager_init ( void ) +{ + /* toggle actions */ + toggleaction_group_others = ui_manager_new_action_group("toggleaction_others"); + gtk_action_group_add_toggle_actions( + toggleaction_group_others , toggleaction_entries_others , + G_N_ELEMENTS(toggleaction_entries_others) , NULL ); + + /* radio actions */ + radioaction_group_anamode = ui_manager_new_action_group("radioaction_anamode"); + gtk_action_group_add_radio_actions( + radioaction_group_anamode , radioaction_entries_anamode , + G_N_ELEMENTS(radioaction_entries_anamode) , 0 , G_CALLBACK(action_anamode) , NULL ); + + radioaction_group_anatype = ui_manager_new_action_group("radioaction_anatype"); + gtk_action_group_add_radio_actions( + radioaction_group_anatype , radioaction_entries_anatype , + G_N_ELEMENTS(radioaction_entries_anatype) , 0 , G_CALLBACK(action_anatype) , NULL ); + + radioaction_group_scomode = ui_manager_new_action_group("radioaction_scomode"); + gtk_action_group_add_radio_actions( + radioaction_group_scomode , radioaction_entries_scomode , + G_N_ELEMENTS(radioaction_entries_scomode) , 0 , G_CALLBACK(action_scomode) , NULL ); + + radioaction_group_vprmode = ui_manager_new_action_group("radioaction_vprmode"); + gtk_action_group_add_radio_actions( + radioaction_group_vprmode , radioaction_entries_vprmode , + G_N_ELEMENTS(radioaction_entries_vprmode) , 0 , G_CALLBACK(action_vprmode) , NULL ); + + radioaction_group_wshmode = ui_manager_new_action_group("radioaction_wshmode"); + gtk_action_group_add_radio_actions( + radioaction_group_wshmode , radioaction_entries_wshmode , + G_N_ELEMENTS(radioaction_entries_wshmode) , 0 , G_CALLBACK(action_wshmode) , NULL ); + + radioaction_group_refrate = ui_manager_new_action_group("radioaction_refrate"); + gtk_action_group_add_radio_actions( + radioaction_group_refrate , radioaction_entries_refrate , + G_N_ELEMENTS(radioaction_entries_refrate) , 0 , G_CALLBACK(action_refrate) , NULL ); + + radioaction_group_anafoff = ui_manager_new_action_group("radioaction_anafoff"); + gtk_action_group_add_radio_actions( + radioaction_group_anafoff , radioaction_entries_anafoff , + G_N_ELEMENTS(radioaction_entries_anafoff) , 0 , G_CALLBACK(action_anafoff) , NULL ); + + radioaction_group_peafoff = ui_manager_new_action_group("radioaction_peafoff"); + gtk_action_group_add_radio_actions( + radioaction_group_peafoff , radioaction_entries_peafoff , + G_N_ELEMENTS(radioaction_entries_peafoff) , 0 , G_CALLBACK(action_peafoff) , NULL ); + + radioaction_group_vismode = ui_manager_new_action_group("radioaction_vismode"); + gtk_action_group_add_radio_actions( + radioaction_group_vismode , radioaction_entries_vismode , + G_N_ELEMENTS(radioaction_entries_vismode) , 0 , G_CALLBACK(action_vismode) , NULL ); + + radioaction_group_viewtime = ui_manager_new_action_group("radioaction_viewtime"); + gtk_action_group_add_radio_actions( + radioaction_group_viewtime , radioaction_entries_viewtime , + G_N_ELEMENTS(radioaction_entries_viewtime) , 0 , G_CALLBACK(action_viewtime) , NULL ); + + /* normal actions */ + action_group_playback = ui_manager_new_action_group("action_playback"); + gtk_action_group_add_actions( + action_group_playback , action_entries_playback , + G_N_ELEMENTS(action_entries_playback) , NULL ); + + action_group_playlist = ui_manager_new_action_group("action_playlist"); + gtk_action_group_add_actions( + action_group_playlist , action_entries_playlist , + G_N_ELEMENTS(action_entries_playlist) , NULL ); + + action_group_visualization = ui_manager_new_action_group("action_visualization"); + gtk_action_group_add_actions( + action_group_visualization , action_entries_visualization , + G_N_ELEMENTS(action_entries_visualization) , NULL ); + + action_group_view = ui_manager_new_action_group("action_view"); + gtk_action_group_add_actions( + action_group_view , action_entries_view , + G_N_ELEMENTS(action_entries_view) , NULL ); + + action_group_others = ui_manager_new_action_group("action_others"); + gtk_action_group_add_actions( + action_group_others , action_entries_others , + G_N_ELEMENTS(action_entries_others) , NULL ); + + action_group_playlist_add = ui_manager_new_action_group("action_playlist_add"); + gtk_action_group_add_actions( + action_group_playlist_add, action_entries_playlist_add, + G_N_ELEMENTS(action_entries_playlist_add), NULL ); + + action_group_playlist_select = ui_manager_new_action_group("action_playlist_select"); + gtk_action_group_add_actions( + action_group_playlist_select, action_entries_playlist_select, + G_N_ELEMENTS(action_entries_playlist_select), NULL ); + + action_group_playlist_delete = ui_manager_new_action_group("action_playlist_delete"); + gtk_action_group_add_actions( + action_group_playlist_delete, action_entries_playlist_delete, + G_N_ELEMENTS(action_entries_playlist_delete), NULL ); + + action_group_playlist_sort = ui_manager_new_action_group("action_playlist_sort"); + gtk_action_group_add_actions( + action_group_playlist_sort, action_entries_playlist_sort, + G_N_ELEMENTS(action_entries_playlist_sort), NULL ); + + action_group_equalizer = ui_manager_new_action_group("action_equalizer"); + gtk_action_group_add_actions( + action_group_equalizer, action_entries_equalizer, + G_N_ELEMENTS(action_entries_equalizer), NULL); + + /* ui */ + ui_manager = gtk_ui_manager_new(); + gtk_ui_manager_insert_action_group( ui_manager , toggleaction_group_others , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anamode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anatype , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_scomode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_vprmode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_wshmode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_refrate , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anafoff , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_peafoff , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_vismode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_viewtime , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playback , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_visualization , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_view , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_others , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_add , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_select , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_delete , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_sort , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_equalizer , 0 ); + + return; +} + +#ifdef GDK_WINDOWING_QUARTZ +static GtkWidget *carbon_menubar; +#endif + +static void +ui_manager_create_menus_init_pmenu( gchar * path ) +{ + GtkWidget *plugins_menu_item = gtk_ui_manager_get_widget( ui_manager , path ); + if ( plugins_menu_item ) + { + /* initially set count of items under plugins_menu_item to 0 */ + g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(0) ); + /* and since it's 0, hide the plugins_menu_item */ + gtk_widget_hide( plugins_menu_item ); + } + return; +} + + +void +ui_manager_create_menus ( void ) +{ + GError *gerr = NULL; + + /* attach xml menu definitions */ + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/mainwin.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI<ui/mainwin.ui>: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + /* create GtkMenu widgets using path from xml definitions */ + mainwin_songname_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/songname-menu" ); + mainwin_visualization_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/visualization" ); + mainwin_playback_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/playback" ); + mainwin_playlist_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/playlist" ); + mainwin_view_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/view" ); + mainwin_general_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu" ); + + /* initialize plugins-menu for mainwin-menus */ + ui_manager_create_menus_init_pmenu( "/mainwin-menus/main-menu/plugins-menu" ); + +#ifdef GDK_WINDOWING_QUARTZ + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/carbon-menubar.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI<ui/carbon-menubar.ui>: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + carbon_menubar = ui_manager_get_popup_menu( ui_manager , "/carbon-menubar/main-menu" ); + sync_menu_takeover_menu(GTK_MENU_SHELL(carbon_menubar)); +#endif + + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/playlist.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI<ui/playlist.ui>: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + playlistwin_popup_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/playlist-rightclick-menu"); + + playlistwin_pladd_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/add-menu"); + playlistwin_pldel_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/del-menu"); + playlistwin_plsel_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/select-menu"); + playlistwin_plsort_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/misc-menu"); + playlistwin_pllist_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/playlist-menu"); + + /* initialize plugins-menu for playlist-menus */ + ui_manager_create_menus_init_pmenu( "/playlist-menus/playlist-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/add-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/del-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/select-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/misc-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/playlist-rightclick-menu/plugins-menu" ); + + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/equalizer.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI<ui/equalizer.ui>: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + equalizerwin_presets_menu = ui_manager_get_popup_menu(ui_manager, "/equalizer-menus/preset-menu"); + + menu_created = TRUE; + + return; +} + + +GtkAccelGroup * +ui_manager_get_accel_group ( void ) +{ + return gtk_ui_manager_get_accel_group( ui_manager ); +} + + +GtkWidget * +ui_manager_get_popup_menu ( GtkUIManager * self , const gchar * path ) +{ + GtkWidget *menu_item = gtk_ui_manager_get_widget( self , path ); + + if (GTK_IS_MENU_ITEM(menu_item)) + return gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)); + else + return NULL; +} + + +static void +menu_popup_pos_func (GtkMenu * menu , gint * x , gint * y , gboolean * push_in , gint * point ) +{ + GtkRequisition requisition; + gint screen_width; + gint screen_height; + + gtk_widget_size_request(GTK_WIDGET(menu), &requisition); + + screen_width = gdk_screen_width(); + screen_height = gdk_screen_height(); + + *x = CLAMP(point[0] - 2, 0, MAX(0, screen_width - requisition.width)); + *y = CLAMP(point[1] - 2, 0, MAX(0, screen_height - requisition.height)); + + *push_in = FALSE; +} + + +void +ui_manager_popup_menu_show ( GtkMenu * menu , gint x , gint y , guint button , guint time ) +{ + gint pos[2]; + pos[0] = x; + pos[1] = y; + + gtk_menu_popup( menu , NULL , NULL , + (GtkMenuPositionFunc) menu_popup_pos_func , pos , button , time ); +} + + + +/******************************/ +/* plugin-available functions */ + +#define _MP_GWID(y) gtk_ui_manager_get_widget( ui_manager , y ) + +static GtkWidget* +audacious_menu_plugin_menuwid( menu_id ) +{ + switch (menu_id) + { + case AUDACIOUS_MENU_MAIN: + return _MP_GWID("/mainwin-menus/main-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST: + return _MP_GWID("/playlist-menus/playlist-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_RCLICK: + return _MP_GWID("/playlist-menus/playlist-rightclick-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_ADD: + return _MP_GWID("/playlist-menus/add-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_REMOVE: + return _MP_GWID("/playlist-menus/del-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_SELECT: + return _MP_GWID("/playlist-menus/select-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_MISC: + return _MP_GWID("/playlist-menus/misc-menu/plugins-menu"); + default: + return NULL; + } +} + + +gint +menu_plugin_item_add( gint menu_id , GtkWidget * item ) +{ + if ( menu_created ) + { + GtkWidget *plugins_menu = NULL; + GtkWidget *plugins_menu_item = audacious_menu_plugin_menuwid( menu_id ); + if ( plugins_menu_item ) + { + gint ic = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(plugins_menu_item),"ic")); + if ( ic == 0 ) /* no items under plugins_menu_item, create the submenu */ + { + plugins_menu = gtk_menu_new(); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(plugins_menu_item), plugins_menu ); + } + else /* items available under plugins_menu_item, pick the existing submenu */ + { + plugins_menu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(plugins_menu_item) ); + if ( !plugins_menu ) return -1; + } + gtk_menu_shell_append( GTK_MENU_SHELL(plugins_menu) , item ); + gtk_widget_show( plugins_menu_item ); + g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(++ic) ); + return 0; /* success */ + } + } + return -1; /* failure */ +} + + +gint +menu_plugin_item_remove( gint menu_id , GtkWidget * item ) +{ + if ( menu_created ) + { + GtkWidget *plugins_menu = NULL; + GtkWidget *plugins_menu_item = audacious_menu_plugin_menuwid( menu_id ); + if ( plugins_menu_item ) + { + gint ic = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(plugins_menu_item),"ic")); + if ( ic > 0 ) + { + plugins_menu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(plugins_menu_item) ); + if ( plugins_menu ) + { + /* remove the plugin-added entry */ + gtk_container_remove( GTK_CONTAINER(plugins_menu) , item ); + g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(--ic) ); + if ( ic == 0 ) /* if the menu is empty now, destroy it */ + { + gtk_menu_item_remove_submenu( GTK_MENU_ITEM(plugins_menu_item) ); + gtk_widget_destroy( plugins_menu ); + gtk_widget_hide( plugins_menu_item ); + } + return 0; /* success */ + } + } + } + } + return -1; /* failure */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_manager.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,77 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_MANAGER_H +#define AUDACIOUS_UI_MANAGER_H + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +GtkWidget *mainwin_songname_menu; +GtkWidget *mainwin_general_menu; +GtkWidget *mainwin_visualization_menu; +GtkWidget *mainwin_playback_menu; +GtkWidget *mainwin_playlist_menu; +GtkWidget *mainwin_view_menu; + +GtkWidget *playlistwin_pladd_menu; +GtkWidget *playlistwin_pldel_menu; +GtkWidget *playlistwin_plsel_menu; +GtkWidget *playlistwin_plsort_menu; +GtkWidget *playlistwin_pllist_menu; +GtkWidget *playlistwin_popup_menu; + +GtkWidget *equalizerwin_presets_menu; + +GtkActionGroup *toggleaction_group_others; +GtkActionGroup *radioaction_group_anamode; /* Analyzer mode */ +GtkActionGroup *radioaction_group_anatype; /* Analyzer type */ +GtkActionGroup *radioaction_group_scomode; /* Scope mode */ +GtkActionGroup *radioaction_group_vprmode; /* Voiceprint mode */ +GtkActionGroup *radioaction_group_wshmode; /* WindowShade VU mode */ +GtkActionGroup *radioaction_group_refrate; /* Refresh rate */ +GtkActionGroup *radioaction_group_anafoff; /* Analyzer Falloff */ +GtkActionGroup *radioaction_group_peafoff; /* Peak Falloff */ +GtkActionGroup *radioaction_group_vismode; /* Visualization mode */ +GtkActionGroup *radioaction_group_viewtime; /* View time (remaining/elapsed) */ +GtkActionGroup *action_group_playback; +GtkActionGroup *action_group_visualization; +GtkActionGroup *action_group_view; +GtkActionGroup *action_group_others; +GtkActionGroup *action_group_playlist; +GtkActionGroup *action_group_playlist_add; +GtkActionGroup *action_group_playlist_select; +GtkActionGroup *action_group_playlist_delete; +GtkActionGroup *action_group_playlist_sort; +GtkActionGroup *action_group_equalizer; + + +void ui_manager_init ( void ); +void ui_manager_create_menus ( void ); +GtkAccelGroup * ui_manager_get_accel_group ( void ); +GtkWidget * ui_manager_get_popup_menu ( GtkUIManager * , const gchar * ); +void ui_manager_popup_menu_show( GtkMenu * , gint , gint , guint , guint ); +#define popup_menu_show(x1,x2,x3,x4,x5) ui_manager_popup_menu_show(x1,x2,x3,x4,x5) + +G_END_DECLS + +#endif /* AUDACIOUS_UI_MANAGER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_playlist.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,1950 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2006 Audacious development team. + * + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +/* #define AUD_DEBUG 1 */ + +#include "ui_playlist.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gdk/gdk.h> +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <string.h> + +#include "platform/smartinclude.h" + +#include <unistd.h> +#include <errno.h> + +#include "actions-playlist.h" +#include "dnd.h" +#if 0 +#include "input.h" +#include "main.h" +#include "playback.h" +#include "playlist.h" +#include "playlist_container.h" +#include "strings.h" +#endif +#include "ui_dock.h" +#include "ui_equalizer.h" +#if 0 +#include "ui_fileinfo.h" +#include "ui_fileopener.h" +#endif +#include "ui_main.h" +#include "ui_manager.h" +#include "ui_playlist_evlisteners.h" +#if 0 +#include "ui_playlist_manager.h" +#endif +#include "util.h" + +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_textbox.h" +#include "ui_skinned_playlist_slider.h" +#include "ui_skinned_playlist.h" + +#include "icons-stock.h" +#include "images/audacious_playlist.xpm" + +GtkWidget *playlistwin; + +static GMutex *resize_mutex = NULL; + +static GtkWidget *playlistwin_list = NULL; +static GtkWidget *playlistwin_shade, *playlistwin_close; + +static gboolean playlistwin_hint_flag = FALSE; + +static GtkWidget *playlistwin_slider; +static GtkWidget *playlistwin_time_min, *playlistwin_time_sec; +static GtkWidget *playlistwin_info, *playlistwin_sinfo; +static GtkWidget *playlistwin_srew, *playlistwin_splay; +static GtkWidget *playlistwin_spause, *playlistwin_sstop; +static GtkWidget *playlistwin_sfwd, *playlistwin_seject; +static GtkWidget *playlistwin_sscroll_up, *playlistwin_sscroll_down; + +static void playlistwin_select_search_cbt_cb(GtkWidget *called_cbt, + gpointer other_cbt); +static gboolean playlistwin_select_search_kp_cb(GtkWidget *entry, + GdkEventKey *event, + gpointer searchdlg_win); + +static gboolean playlistwin_resizing = FALSE; +static gint playlistwin_resize_x, playlistwin_resize_y; + +gboolean +playlistwin_is_shaded(void) +{ + return config.playlist_shaded; +} + +gint +playlistwin_get_width(void) +{ + config.playlist_width /= PLAYLISTWIN_WIDTH_SNAP; + config.playlist_width *= PLAYLISTWIN_WIDTH_SNAP; + return config.playlist_width; +} + +gint +playlistwin_get_height_unshaded(void) +{ + config.playlist_height /= PLAYLISTWIN_HEIGHT_SNAP; + config.playlist_height *= PLAYLISTWIN_HEIGHT_SNAP; + return config.playlist_height; +} + +gint +playlistwin_get_height_shaded(void) +{ + return PLAYLISTWIN_SHADED_HEIGHT; +} + +gint +playlistwin_get_height(void) +{ + if (playlistwin_is_shaded()) + return playlistwin_get_height_shaded(); + else + return playlistwin_get_height_unshaded(); +} + +static void +playlistwin_update_info(Playlist *playlist) +{ +#if 0 + gchar *text, *sel_text, *tot_text; + gulong selection, total; + gboolean selection_more, total_more; + + aud_playlist_get_total_time(playlist, &total, &selection, &total_more, &selection_more); + + if (selection > 0 || (selection == 0 && !selection_more)) { + if (selection > 3600) + sel_text = + g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", selection / 3600, + (selection / 60) % 60, selection % 60, + (selection_more ? "+" : "")); + else + sel_text = + g_strdup_printf("%lu:%-2.2lu%s", selection / 60, + selection % 60, (selection_more ? "+" : "")); + } + else + sel_text = g_strdup("?"); + if (total > 0 || (total == 0 && !total_more)) { + if (total > 3600) + tot_text = + g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", total / 3600, + (total / 60) % 60, total % 60, + total_more ? "+" : ""); + else + tot_text = + g_strdup_printf("%lu:%-2.2lu%s", total / 60, total % 60, + total_more ? "+" : ""); + } + else + tot_text = g_strdup("?"); + text = g_strconcat(sel_text, "/", tot_text, NULL); + ui_skinned_textbox_set_text(playlistwin_info, text ? text : ""); + g_free(text); + g_free(tot_text); + g_free(sel_text); +#endif +} + +static void +playlistwin_update_sinfo(Playlist *playlist) +{ +#if 0 + gchar *posstr, *timestr, *title, *info; + gint pos, time; + + pos = aud_playlist_get_position(playlist); + title = aud_playlist_get_songtitle(playlist, pos); + + if (!title) { + ui_skinned_textbox_set_text(playlistwin_sinfo, ""); + return; + } + + aud_convert_title_text(title); + + time = aud_playlist_get_songtime(playlist, pos); + + if (config.show_numbers_in_pl) + posstr = g_strdup_printf("%d. ", pos + 1); + else + posstr = g_strdup(""); + + if (time != -1) { + timestr = g_strdup_printf(" (%d:%-2.2d)", time / 60000, + (time / 1000) % 60); + } + else + timestr = g_strdup(""); + + info = g_strdup_printf("%s%s%s", posstr, title, timestr); + + g_free(posstr); + g_free(title); + g_free(timestr); + + ui_skinned_textbox_set_text(playlistwin_sinfo, info ? info : ""); + g_free(info); +#endif +} + +gboolean +playlistwin_item_visible(gint index) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), FALSE); + + if (index >= UI_SKINNED_PLAYLIST(playlistwin_list)->first && + index < (UI_SKINNED_PLAYLIST(playlistwin_list)->first + UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible) ) { + return TRUE; + } + return FALSE; +} + +gint +playlistwin_list_get_visible_count(void) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); + + return UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible; +} + +gint +playlistwin_list_get_first(void) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); + + return UI_SKINNED_PLAYLIST(playlistwin_list)->first; +} + +gint +playlistwin_get_toprow(void) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); + + return (UI_SKINNED_PLAYLIST(playlistwin_list)->first); +} + +void +playlistwin_set_toprow(gint toprow) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) + UI_SKINNED_PLAYLIST(playlistwin_list)->first = toprow; +#if 0 + g_cond_signal(cond_scan); +#endif + playlistwin_update_list(aud_playlist_get_active()); +} + +void +playlistwin_update_list(Playlist *playlist) +{ + /* this can happen early on. just bail gracefully. */ + g_return_if_fail(playlistwin_list); + + playlistwin_update_info(playlist); + playlistwin_update_sinfo(playlist); + gtk_widget_queue_draw(playlistwin_list); + gtk_widget_queue_draw(playlistwin_slider); +} + +static void +playlistwin_set_geometry_hints(gboolean shaded) +{ + GdkGeometry geometry; + GdkWindowHints mask; + + geometry.min_width = PLAYLISTWIN_MIN_WIDTH; + geometry.max_width = G_MAXUINT16; + + geometry.width_inc = PLAYLISTWIN_WIDTH_SNAP; + geometry.height_inc = PLAYLISTWIN_HEIGHT_SNAP; + + if (shaded) { + geometry.min_height = PLAYLISTWIN_SHADED_HEIGHT; + geometry.max_height = PLAYLISTWIN_SHADED_HEIGHT; + geometry.base_height = PLAYLISTWIN_SHADED_HEIGHT; + } + else { + geometry.min_height = PLAYLISTWIN_MIN_HEIGHT; + geometry.max_height = G_MAXUINT16; + } + + mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_RESIZE_INC; + + gtk_window_set_geometry_hints(GTK_WINDOW(playlistwin), + playlistwin, &geometry, mask); +} + +void +playlistwin_set_sinfo_font(gchar *font) +{ + gchar *tmp = NULL, *tmp2 = NULL; + + g_return_if_fail(font); + AUDDBG("Attempt to set font \"%s\"\n", font); + + tmp = g_strdup(font); + g_return_if_fail(tmp); + + *strrchr(tmp, ' ') = '\0'; + tmp2 = g_strdup_printf("%s 8", tmp); + g_return_if_fail(tmp2); + + ui_skinned_textbox_set_xfont(playlistwin_sinfo, !config.mainwin_use_bitmapfont, tmp2); + + g_free(tmp); + g_free(tmp2); +} + +void +playlistwin_set_sinfo_scroll(gboolean scroll) +{ + if(playlistwin_is_shaded()) + ui_skinned_textbox_set_scroll(playlistwin_sinfo, config.autoscroll); + else + ui_skinned_textbox_set_scroll(playlistwin_sinfo, FALSE); +} + +void +playlistwin_set_shade(gboolean shaded) +{ + config.playlist_shaded = shaded; + + if (shaded) { + playlistwin_set_sinfo_font(aud_cfg->playlist_font); + playlistwin_set_sinfo_scroll(config.autoscroll); + gtk_widget_show(playlistwin_sinfo); + ui_skinned_set_push_button_data(playlistwin_shade, 128, 45, 150, 42); + ui_skinned_set_push_button_data(playlistwin_close, 138, 45, -1, -1); + } + else { + gtk_widget_hide(playlistwin_sinfo); + playlistwin_set_sinfo_scroll(FALSE); + ui_skinned_set_push_button_data(playlistwin_shade, 157, 3, 62, 42); + ui_skinned_set_push_button_data(playlistwin_close, 167, 3, -1, -1); + } + + dock_shade(get_dock_window_list(), GTK_WINDOW(playlistwin), + playlistwin_get_height()); + + playlistwin_set_geometry_hints(config.playlist_shaded); + + gtk_window_resize(GTK_WINDOW(playlistwin), + playlistwin_get_width(), + playlistwin_get_height()); +} + +static void +playlistwin_set_shade_menu(gboolean shaded) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "roll up playlist editor" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); + + playlistwin_set_shade(shaded); + playlistwin_update_list(aud_playlist_get_active()); +} + +void +playlistwin_shade_toggle(void) +{ + playlistwin_set_shade_menu(!config.playlist_shaded); +} + +static gboolean +playlistwin_release(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + playlistwin_resizing = FALSE; + return FALSE; +} + +void +playlistwin_scroll(gint num) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) + UI_SKINNED_PLAYLIST(playlistwin_list)->first += num; + playlistwin_update_list(aud_playlist_get_active()); +} + +void +playlistwin_scroll_up_pushed(void) +{ + playlistwin_scroll(-3); +} + +void +playlistwin_scroll_down_pushed(void) +{ + playlistwin_scroll(3); +} + +static void +playlistwin_select_all(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_select_all(playlist, TRUE); + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = 0; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = 0; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_max = aud_playlist_get_length(playlist) - 1; + } + playlistwin_update_list(playlist); +} + +static void +playlistwin_select_none(void) +{ + aud_playlist_select_all(aud_playlist_get_active(), FALSE); + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = -1; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = -1; + } + playlistwin_update_list(aud_playlist_get_active()); +} + +static void +playlistwin_select_search(void) +{ + Playlist *playlist = aud_playlist_get_active(); + GtkWidget *searchdlg_win, *searchdlg_table; + GtkWidget *searchdlg_hbox, *searchdlg_logo, *searchdlg_helptext; + GtkWidget *searchdlg_entry_title, *searchdlg_label_title; + GtkWidget *searchdlg_entry_album, *searchdlg_label_album; + GtkWidget *searchdlg_entry_file_name, *searchdlg_label_file_name; + GtkWidget *searchdlg_entry_performer, *searchdlg_label_performer; + GtkWidget *searchdlg_checkbt_clearprevsel; + GtkWidget *searchdlg_checkbt_newplaylist; + GtkWidget *searchdlg_checkbt_autoenqueue; + gint result; + + /* create dialog */ + searchdlg_win = gtk_dialog_new_with_buttons( + _("Search entries in active playlist") , GTK_WINDOW(mainwin) , + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , + GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT , GTK_STOCK_OK , GTK_RESPONSE_ACCEPT , NULL ); + gtk_window_set_position(GTK_WINDOW(searchdlg_win), GTK_WIN_POS_CENTER); + + /* help text and logo */ + searchdlg_hbox = gtk_hbox_new( FALSE , 4 ); + searchdlg_logo = gtk_image_new_from_stock( GTK_STOCK_FIND , GTK_ICON_SIZE_DIALOG ); + searchdlg_helptext = gtk_label_new( _("Select entries in playlist by filling one or more " + "fields. Fields use regular expressions syntax, case-insensitive. If you don't know how " + "regular expressions work, simply insert a literal portion of what you're searching for.") ); + gtk_label_set_line_wrap( GTK_LABEL(searchdlg_helptext) , TRUE ); + gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_logo , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_helptext , FALSE , FALSE , 0 ); + + /* title */ + searchdlg_label_title = gtk_label_new( _("Title: ") ); + searchdlg_entry_title = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_title) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_title) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* album */ + searchdlg_label_album= gtk_label_new( _("Album: ") ); + searchdlg_entry_album= gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_album) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_album) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* artist */ + searchdlg_label_performer = gtk_label_new( _("Artist: ") ); + searchdlg_entry_performer = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_performer) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_performer) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* file name */ + searchdlg_label_file_name = gtk_label_new( _("Filename: ") ); + searchdlg_entry_file_name = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_file_name) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_file_name) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* some options that control behaviour */ + searchdlg_checkbt_clearprevsel = gtk_check_button_new_with_label( + _("Clear previous selection before searching") ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel) , TRUE ); + searchdlg_checkbt_autoenqueue = gtk_check_button_new_with_label( + _("Automatically toggle queue for matching entries") ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue) , FALSE ); + searchdlg_checkbt_newplaylist = gtk_check_button_new_with_label( + _("Create a new playlist with matching entries") ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist) , FALSE ); + g_signal_connect( G_OBJECT(searchdlg_checkbt_autoenqueue) , "clicked" , + G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_newplaylist ); + g_signal_connect( G_OBJECT(searchdlg_checkbt_newplaylist) , "clicked" , + G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_autoenqueue ); + + /* place fields in searchdlg_table */ + searchdlg_table = gtk_table_new( 8 , 2 , FALSE ); + gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 0 , 8 ); + gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 4 , 8 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_hbox , + 0 , 2 , 0 , 1 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_title , + 0 , 1 , 1 , 2 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_title , + 1 , 2 , 1 , 2 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_album, + 0 , 1 , 2 , 3 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_album, + 1 , 2 , 2 , 3 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_performer , + 0 , 1 , 3 , 4 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_performer , + 1 , 2 , 3 , 4 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_file_name , + 0 , 1 , 4 , 5 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_file_name , + 1 , 2 , 4 , 5 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_clearprevsel , + 0 , 2 , 5 , 6 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_autoenqueue , + 0 , 2 , 6 , 7 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_newplaylist , + 0 , 2 , 7 , 8 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); + + gtk_container_set_border_width( GTK_CONTAINER(searchdlg_table) , 5 ); + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(searchdlg_win)->vbox) , searchdlg_table ); + gtk_widget_show_all( searchdlg_win ); + result = gtk_dialog_run( GTK_DIALOG(searchdlg_win) ); + switch(result) + { + case GTK_RESPONSE_ACCEPT: + { + gint matched_entries_num = 0; + /* create a TitleInput tuple with user search data */ + Tuple *tuple = aud_tuple_new(); + gchar *searchdata = NULL; + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_title) ); + AUDDBG("title=\"%s\"\n", searchdata); + aud_tuple_associate_string(tuple, FIELD_TITLE, NULL, searchdata); + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_album) ); + AUDDBG("album=\"%s\"\n", searchdata); + aud_tuple_associate_string(tuple, FIELD_ALBUM, NULL, searchdata); + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_performer) ); + AUDDBG("performer=\"%s\"\n", searchdata); + aud_tuple_associate_string(tuple, FIELD_ARTIST, NULL, searchdata); + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_file_name) ); + AUDDBG("filename=\"%s\"\n", searchdata); + aud_tuple_associate_string(tuple, FIELD_FILE_NAME, NULL, searchdata); + + /* check if previous selection should be cleared before searching */ + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel)) == TRUE ) + playlistwin_select_none(); + /* now send this tuple to the real search function */ + matched_entries_num = aud_playlist_select_search( playlist , tuple , 0 ); + /* we do not need the tuple and its data anymore */ + mowgli_object_unref(tuple); + playlistwin_update_list(aud_playlist_get_active()); + /* check if a new playlist should be created after searching */ + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist)) == TRUE ) + aud_playlist_new_from_selected(); + /* check if matched entries should be queued */ + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue)) == TRUE ) + aud_playlist_queue(aud_playlist_get_active()); + break; + } + default: + break; + } + /* done here :) */ + gtk_widget_destroy( searchdlg_win ); +} + +static void +playlistwin_inverse_selection(void) +{ + aud_playlist_select_invert_all(aud_playlist_get_active()); + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = -1; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = -1; + } + playlistwin_update_list(aud_playlist_get_active()); +} + +static void +playlistwin_resize(gint width, gint height) +{ + gint tx, ty; + gint dx, dy; + + g_return_if_fail(width > 0 && height > 0); + + tx = (width - PLAYLISTWIN_MIN_WIDTH) / PLAYLISTWIN_WIDTH_SNAP; + tx = (tx * PLAYLISTWIN_WIDTH_SNAP) + PLAYLISTWIN_MIN_WIDTH; + if (tx < PLAYLISTWIN_MIN_WIDTH) + tx = PLAYLISTWIN_MIN_WIDTH; + + if (!config.playlist_shaded) + { + ty = (height - PLAYLISTWIN_MIN_HEIGHT) / PLAYLISTWIN_HEIGHT_SNAP; + ty = (ty * PLAYLISTWIN_HEIGHT_SNAP) + PLAYLISTWIN_MIN_HEIGHT; + if (ty < PLAYLISTWIN_MIN_HEIGHT) + ty = PLAYLISTWIN_MIN_HEIGHT; + } + else + ty = config.playlist_height; + + if (tx == config.playlist_width && ty == config.playlist_height) + return; + + /* difference between previous size and new size */ + dx = tx - config.playlist_width; + dy = ty - config.playlist_height; + + config.playlist_width = width = tx; + config.playlist_height = height = ty; + + g_mutex_lock(resize_mutex); + ui_skinned_playlist_resize_relative(playlistwin_list, dx, dy); + + ui_skinned_playlist_slider_move_relative(playlistwin_slider, dx); + ui_skinned_playlist_slider_resize_relative(playlistwin_slider, dy); + + playlistwin_update_sinfo(aud_playlist_get_active()); + + ui_skinned_button_move_relative(playlistwin_shade, dx, 0); + ui_skinned_button_move_relative(playlistwin_close, dx, 0); + ui_skinned_textbox_move_relative(playlistwin_time_min, dx, dy); + ui_skinned_textbox_move_relative(playlistwin_time_sec, dx, dy); + ui_skinned_textbox_move_relative(playlistwin_info, dx, dy); + ui_skinned_button_move_relative(playlistwin_srew, dx, dy); + ui_skinned_button_move_relative(playlistwin_splay, dx, dy); + ui_skinned_button_move_relative(playlistwin_spause, dx, dy); + ui_skinned_button_move_relative(playlistwin_sstop, dx, dy); + ui_skinned_button_move_relative(playlistwin_sfwd, dx, dy); + ui_skinned_button_move_relative(playlistwin_seject, dx, dy); + ui_skinned_button_move_relative(playlistwin_sscroll_up, dx, dy); + ui_skinned_button_move_relative(playlistwin_sscroll_down, dx, dy); + + gtk_widget_set_size_request(playlistwin_sinfo, playlistwin_get_width() - 35, + aud_active_skin->properties.textbox_bitmap_font_height); + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(playlistwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + g_signal_emit_by_name(child, "redraw"); + } + g_mutex_unlock(resize_mutex); +} + +static void +playlistwin_motion(GtkWidget * widget, + GdkEventMotion * event, + gpointer callback_data) +{ + GdkEvent *gevent; + + /* + * GDK2's resize is broken and doesn't really play nice, so we have + * to do all of this stuff by hand. + */ + if (playlistwin_resizing == TRUE) + { + if (event->x + playlistwin_resize_x != playlistwin_get_width() || + event->y + playlistwin_resize_y != playlistwin_get_height()) + { + playlistwin_resize(event->x + playlistwin_resize_x, + event->y + playlistwin_resize_y); + gdk_window_resize(playlistwin->window, + config.playlist_width, playlistwin_get_height()); + gdk_flush(); + } + } + else if (dock_is_moving(GTK_WINDOW(playlistwin))) + dock_move_motion(GTK_WINDOW(playlistwin), event); + + while ((gevent = gdk_event_get()) != NULL) gdk_event_free(gevent); +} + +static void +playlistwin_show_filebrowser(void) +{ +#if 0 + run_filebrowser(NO_PLAY_BUTTON); +#endif +} + +static void +playlistwin_fileinfo(void) +{ +#if 0 + Playlist *playlist = aud_playlist_get_active(); + + /* Show the first selected file, or the current file if nothing is + * selected */ + GList *list = aud_playlist_get_selected(playlist); + if (list) { + ui_fileinfo_show(playlist, GPOINTER_TO_INT(list->data)); + g_list_free(list); + } + else + + ui_fileinfo_show_current(playlist); +#endif +} + +static void +show_playlist_save_error(GtkWindow *parent, + const gchar *filename) +{ + GtkWidget *dialog; + + g_return_if_fail(GTK_IS_WINDOW(parent)); + g_return_if_fail(filename); + + dialog = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Error writing playlist \"%s\": %s"), + filename, strerror(errno)); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +static gboolean +show_playlist_overwrite_prompt(GtkWindow * parent, + const gchar * filename) +{ + GtkWidget *dialog; + gint result; + + g_return_val_if_fail(GTK_IS_WINDOW(parent), FALSE); + g_return_val_if_fail(filename != NULL, FALSE); + + dialog = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + _("%s already exist. Continue?"), + filename); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + result = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + return (result == GTK_RESPONSE_YES); +} + +static void +show_playlist_save_format_error(GtkWindow * parent, + const gchar * filename) +{ + const gchar *markup = + N_("<b><big>Unable to save playlist.</big></b>\n\n" + "Unknown file type for '%s'.\n"); + + GtkWidget *dialog; + + g_return_if_fail(GTK_IS_WINDOW(parent)); + g_return_if_fail(filename != NULL); + + dialog = + gtk_message_dialog_new_with_markup(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _(markup), + filename); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +static void +playlistwin_save_playlist(const gchar * filename) +{ + PlaylistContainer *plc; + gchar *ext = strrchr(filename, '.') + 1; + + plc = aud_playlist_container_find(ext); + if (plc == NULL) { + show_playlist_save_format_error(GTK_WINDOW(playlistwin), filename); + return; + } + + aud_str_replace_in(&aud_cfg->playlist_path, g_path_get_dirname(filename)); + + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + if (!show_playlist_overwrite_prompt(GTK_WINDOW(playlistwin), filename)) + return; + + if (!aud_playlist_save(aud_playlist_get_active(), filename)) + show_playlist_save_error(GTK_WINDOW(playlistwin), filename); +} + +static void +playlistwin_load_playlist(const gchar * filename) +{ + const gchar *title; + Playlist *playlist = aud_playlist_get_active(); + + g_return_if_fail(filename != NULL); + + aud_str_replace_in(&aud_cfg->playlist_path, g_path_get_dirname(filename)); + + aud_playlist_clear(playlist); + mainwin_clear_song_info(); + + aud_playlist_load(playlist, filename); + title = aud_playlist_get_current_name(playlist); + if(!title || !title[0]) + aud_playlist_set_current_name(playlist, filename); +} + +static gchar * +playlist_file_selection_load(const gchar * title, + const gchar * default_filename) +{ + GtkWidget *dialog; + gchar *filename; + + g_return_val_if_fail(title != NULL, NULL); + + dialog = make_filebrowser(title, FALSE); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), aud_cfg->playlist_path); + if (default_filename) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), default_filename); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + else + filename = NULL; + + gtk_widget_destroy(dialog); + return filename; +} + +static void +on_static_toggle(GtkToggleButton *button, gpointer data) +{ + Playlist *playlist = aud_playlist_get_active(); + + playlist->attribute = + gtk_toggle_button_get_active(button) ? + playlist->attribute | PLAYLIST_STATIC : + playlist->attribute & ~PLAYLIST_STATIC; +} + +static void +on_relative_toggle(GtkToggleButton *button, gpointer data) +{ + Playlist *playlist = aud_playlist_get_active(); + + playlist->attribute = + gtk_toggle_button_get_active(button) ? + playlist->attribute | PLAYLIST_USE_RELATIVE : + playlist->attribute & ~PLAYLIST_USE_RELATIVE; +} + +static gchar * +playlist_file_selection_save(const gchar * title, + const gchar * default_filename) +{ + GtkWidget *dialog; + gchar *filename; + GtkWidget *hbox; + GtkWidget *toggle, *toggle2; + + g_return_val_if_fail(title != NULL, NULL); + + dialog = make_filebrowser(title, TRUE); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), aud_cfg->playlist_path); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), default_filename); + + hbox = gtk_hbox_new(FALSE, 5); + + /* static playlist */ + toggle = gtk_check_button_new_with_label(_("Save as Static Playlist")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), + (aud_playlist_get_active()->attribute & PLAYLIST_STATIC) ? TRUE : FALSE); + g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(on_static_toggle), dialog); + gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0); + + /* use relative path */ + toggle2 = gtk_check_button_new_with_label(_("Use Relative Path")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2), + (aud_playlist_get_active()->attribute & PLAYLIST_USE_RELATIVE) ? TRUE : FALSE); + g_signal_connect(G_OBJECT(toggle2), "toggled", G_CALLBACK(on_relative_toggle), dialog); + gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0); + + gtk_widget_show_all(hbox); + gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), hbox); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + else + filename = NULL; + + gtk_widget_destroy(dialog); + return filename; +} + +void +playlistwin_select_playlist_to_load(const gchar * default_filename) +{ + gchar *filename = + playlist_file_selection_load(_("Load Playlist"), default_filename); + + if (filename) { + playlistwin_load_playlist(filename); + g_free(filename); + } +} + +static void +playlistwin_select_playlist_to_save(const gchar * default_filename) +{ + gchar *dot = NULL, *basename = NULL; + gchar *filename = + playlist_file_selection_save(_("Save Playlist"), default_filename); + + if (filename) { + /* Default extension */ + basename = g_path_get_basename(filename); + dot = strrchr(basename, '.'); + if( dot == NULL || dot == basename) { + gchar *oldname = filename; +#ifdef HAVE_XSPF_PLAYLIST + filename = g_strconcat(oldname, ".xspf", NULL); +#else + filename = g_strconcat(oldname, ".m3u", NULL); +#endif + g_free(oldname); + } + g_free(basename); + + playlistwin_save_playlist(filename); + g_free(filename); + } +} + +#define REGION_L(x1,x2,y1,y2) \ + (event->x >= (x1) && event->x < (x2) && \ + event->y >= config.playlist_height - (y1) && \ + event->y < config.playlist_height - (y2)) + +#define REGION_R(x1,x2,y1,y2) \ + (event->x >= playlistwin_get_width() - (x1) && \ + event->x < playlistwin_get_width() - (x2) && \ + event->y >= config.playlist_height - (y1) && \ + event->y < config.playlist_height - (y2)) + +static void +playlistwin_scrolled(GtkWidget * widget, + GdkEventScroll * event, + gpointer callback_data) +{ + if (event->direction == GDK_SCROLL_DOWN) + playlistwin_scroll(config.scroll_pl_by); + + if (event->direction == GDK_SCROLL_UP) + playlistwin_scroll(-config.scroll_pl_by); +#if 0 + g_cond_signal(cond_scan); +#endif +} + +static gboolean +playlistwin_press(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + gint xpos, ypos; + GtkRequisition req; + + gtk_window_get_position(GTK_WINDOW(playlistwin), &xpos, &ypos); + + if (event->button == 1 && !config.show_wm_decorations && + ((!config.playlist_shaded && + event->x > playlistwin_get_width() - 20 && + event->y > config.playlist_height - 20) || + (config.playlist_shaded && + event->x >= playlistwin_get_width() - 31 && + event->x < playlistwin_get_width() - 22))) { + + if (event->type != GDK_2BUTTON_PRESS && + event->type != GDK_3BUTTON_PRESS) { + playlistwin_resizing = TRUE; + playlistwin_resize_x = config.playlist_width - event->x; + playlistwin_resize_y = config.playlist_height - event->y; + } + } + else if (event->button == 1 && REGION_L(12, 37, 29, 11)) { + /* ADD button menu */ + gtk_widget_size_request(playlistwin_pladd_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_pladd_menu), + xpos + 12, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_L(41, 66, 29, 11)) { + /* SUB button menu */ + gtk_widget_size_request(playlistwin_pldel_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_pldel_menu), + xpos + 40, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_L(70, 95, 29, 11)) { + /* SEL button menu */ + gtk_widget_size_request(playlistwin_plsel_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsel_menu), + xpos + 68, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_L(99, 124, 29, 11)) { + /* MISC button menu */ + gtk_widget_size_request(playlistwin_plsort_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsort_menu), + xpos + 100, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_R(46, 23, 29, 11)) { + /* LIST button menu */ + gtk_widget_size_request(playlistwin_pllist_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_pllist_menu), + xpos + playlistwin_get_width() - req.width - 12, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + (config.easy_move || event->y < 14)) + { + return FALSE; + } + else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS + && event->y < 14) { + /* double click on title bar */ + playlistwin_shade_toggle(); + if (dock_is_moving(GTK_WINDOW(playlistwin))) + dock_move_release(GTK_WINDOW(playlistwin)); + return TRUE; + } + else if (event->button == 3) { + /* + * Pop up the main menu a few pixels down to avoid + * anything to be selected initially. + */ + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root, + event->y_root + 2, 3, event->time); + } + + return TRUE; +} + +static gboolean +playlistwin_delete(GtkWidget * w, gpointer data) +{ + playlistwin_hide(); + return TRUE; +} + +static gboolean +playlistwin_keypress_up_down_handler(UiSkinnedPlaylist * pl, + gboolean up, guint state) +{ + Playlist *playlist = aud_playlist_get_active(); + if ((!(pl->prev_selected || pl->first) && up) || + ((pl->prev_selected >= aud_playlist_get_length(playlist) - 1) && !up)) + return FALSE; + + if ((state & GDK_MOD1_MASK) && (state & GDK_SHIFT_MASK)) + return FALSE; + if (!(state & GDK_MOD1_MASK)) + aud_playlist_select_all(playlist, FALSE); + + if (pl->prev_selected == -1 || + (!playlistwin_item_visible(pl->prev_selected) && + !(state & GDK_SHIFT_MASK && pl->prev_min != -1))) { + pl->prev_selected = pl->first; + } + else if (state & GDK_SHIFT_MASK) { + if (pl->prev_min == -1) { + pl->prev_max = pl->prev_selected; + pl->prev_min = pl->prev_selected; + } + pl->prev_max += (up ? -1 : 1); + pl->prev_max = + CLAMP(pl->prev_max, 0, aud_playlist_get_length(playlist) - 1); + + pl->first = MIN(pl->first, pl->prev_max); + pl->first = MAX(pl->first, pl->prev_max - + pl->num_visible + 1); + aud_playlist_select_range(playlist, pl->prev_min, pl->prev_max, TRUE); + return TRUE; + } + else if (state & GDK_MOD1_MASK) { + if (up) + ui_skinned_playlist_move_up(pl); + else + ui_skinned_playlist_move_down(pl); + if (pl->prev_min < pl->first) + pl->first = pl->prev_min; + else if (pl->prev_max >= (pl->first + pl->num_visible)) + pl->first = pl->prev_max - pl->num_visible + 1; + return TRUE; + } + else if (up) + pl->prev_selected--; + else + pl->prev_selected++; + + pl->prev_selected = + CLAMP(pl->prev_selected, 0, aud_playlist_get_length(playlist) - 1); + + if (pl->prev_selected < pl->first) + pl->first--; + else if (pl->prev_selected >= (pl->first + pl->num_visible)) + pl->first++; + + aud_playlist_select_range(playlist, pl->prev_selected, pl->prev_selected, TRUE); + pl->prev_min = -1; + + return TRUE; +} + +/* FIXME: Handle the keys through menu */ + +static gboolean +playlistwin_keypress(GtkWidget * w, GdkEventKey * event, gpointer data) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), FALSE); + Playlist *playlist = aud_playlist_get_active(); + + guint keyval; + gboolean refresh = FALSE; + guint cur_pos; + + if (config.playlist_shaded) + return FALSE; + + switch (keyval = event->keyval) { + case GDK_KP_Up: + case GDK_KP_Down: + case GDK_Up: + case GDK_Down: + refresh = playlistwin_keypress_up_down_handler(UI_SKINNED_PLAYLIST(playlistwin_list), + keyval == GDK_Up + || keyval == GDK_KP_Up, + event->state); + break; + case GDK_Page_Up: + playlistwin_scroll(-UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible); + refresh = TRUE; + break; + case GDK_Page_Down: + playlistwin_scroll(UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible); + refresh = TRUE; + break; + case GDK_Home: + UI_SKINNED_PLAYLIST(playlistwin_list)->first = 0; + refresh = TRUE; + break; + case GDK_End: + UI_SKINNED_PLAYLIST(playlistwin_list)->first = + aud_playlist_get_length(playlist) - UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible; + refresh = TRUE; + break; + case GDK_Return: + if (UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected > -1 + && playlistwin_item_visible(UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected)) { + aud_playlist_set_position(playlist, UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected); + if (!audacious_drct_get_playing()) + audacious_drct_initiate(); + } + refresh = TRUE; + break; + case GDK_3: + if (event->state & GDK_CONTROL_MASK) + playlistwin_fileinfo(); + break; + case GDK_Delete: + if (event->state & GDK_CONTROL_MASK) + aud_playlist_delete(playlist, TRUE); + else + aud_playlist_delete(playlist, FALSE); + break; + case GDK_Insert: + if (event->state & GDK_MOD1_MASK) + mainwin_show_add_url_window(); + else + playlistwin_show_filebrowser(); + break; + case GDK_Left: + case GDK_KP_Left: + case GDK_KP_7: + if (aud_playlist_get_current_length(playlist) != -1) + audacious_drct_seek(CLAMP + (audacious_drct_get_time() - 5000, 0, + aud_playlist_get_current_length(playlist))); + break; + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_9: + if (aud_playlist_get_current_length(playlist) != -1) + audacious_drct_seek(CLAMP + (audacious_drct_get_time() + 5000, 0, + aud_playlist_get_current_length(playlist))); + break; + case GDK_KP_4: + aud_playlist_prev(playlist); + break; + case GDK_KP_6: + aud_playlist_next(playlist); + break; + + case GDK_Escape: + mainwin_minimize_cb(); + break; + case GDK_Tab: + if (event->state & GDK_CONTROL_MASK) { + if (config.player_visible) + gtk_window_present(GTK_WINDOW(mainwin)); + else if (config.equalizer_visible) + gtk_window_present(GTK_WINDOW(equalizerwin)); + } + break; + case GDK_space: + cur_pos=aud_playlist_get_position(playlist); + UI_SKINNED_PLAYLIST(playlistwin_list)->first = + cur_pos - (UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible >> 1); + refresh = TRUE; + break; + default: + return FALSE; + } +#if 0 + if (refresh) { + g_cond_signal(cond_scan); + playlistwin_update_list(aud_playlist_get_active()); + } +#endif + return TRUE; +} + +void +playlistwin_hide_timer(void) +{ + ui_skinned_textbox_set_text(playlistwin_time_min, " "); + ui_skinned_textbox_set_text(playlistwin_time_sec, " "); +} + +void +playlistwin_set_time(gint time, gint length, TimerMode mode) +{ + gchar *text, sign; + + if (mode == TIMER_REMAINING && length != -1) { + time = length - time; + sign = '-'; + } + else + sign = ' '; + + time /= 1000; + + if (time < 0) + time = 0; + if (time > 99 * 60) + time /= 60; + + text = g_strdup_printf("%c%-2.2d", sign, time / 60); + ui_skinned_textbox_set_text(playlistwin_time_min, text); + g_free(text); + + text = g_strdup_printf("%-2.2d", time % 60); + ui_skinned_textbox_set_text(playlistwin_time_sec, text); + g_free(text); +} + +static void +playlistwin_drag_motion(GtkWidget * widget, + GdkDragContext * context, + gint x, gint y, + GtkSelectionData * selection_data, + guint info, guint time, gpointer user_data) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion = TRUE; + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion_x = x; + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion_y = y; + } + playlistwin_update_list(aud_playlist_get_active()); + playlistwin_hint_flag = TRUE; +} + +static void +playlistwin_drag_end(GtkWidget * widget, + GdkDragContext * context, gpointer user_data) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion = FALSE; + playlistwin_hint_flag = FALSE; + playlistwin_update_list(aud_playlist_get_active()); +} + +static void +playlistwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, gint y, + GtkSelectionData * + selection_data, guint info, + guint time, gpointer user_data) +{ + gint pos; + Playlist *playlist = aud_playlist_get_active(); + + g_return_if_fail(selection_data); + + if (!selection_data->data) { + g_message("Received no DND data!"); + return; + } + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list) && + (x < playlistwin_get_width() - 20 || y < config.playlist_height - 38)) { + pos = y / UI_SKINNED_PLAYLIST(playlistwin_list)->fheight + UI_SKINNED_PLAYLIST(playlistwin_list)->first; + + pos = MIN(pos, aud_playlist_get_length(playlist)); + aud_playlist_ins_url(playlist, (gchar *) selection_data->data, pos); + } + else + aud_playlist_add_url(playlist, (gchar *) selection_data->data); +} + +static void +local_playlist_prev(void) +{ + aud_playlist_prev(aud_playlist_get_active()); +} + +static void +local_playlist_next(void) +{ + aud_playlist_next(aud_playlist_get_active()); +} + +static void +playlistwin_create_widgets(void) +{ + /* This function creates the custom widgets used by the playlist editor */ + + /* text box for displaying song title in shaded mode */ + playlistwin_sinfo = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + 4, 4, playlistwin_get_width() - 35, TRUE, SKIN_TEXT); + + playlistwin_set_sinfo_font(aud_cfg->playlist_font); + + playlistwin_shade = ui_skinned_button_new(); + /* shade/unshade window push button */ + if (config.playlist_shaded) + ui_skinned_push_button_setup(playlistwin_shade, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 21, 3, + 9, 9, 128, 45, 150, 42, SKIN_PLEDIT); + else + ui_skinned_push_button_setup(playlistwin_shade, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 21, 3, + 9, 9, 157, 3, 62, 42, SKIN_PLEDIT); + + g_signal_connect(playlistwin_shade, "clicked", playlistwin_shade_toggle, NULL ); + + /* close window push button */ + playlistwin_close = ui_skinned_button_new(); + ui_skinned_push_button_setup(playlistwin_close, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 11, 3, 9, 9, + config.playlist_shaded ? 138 : 167, + config.playlist_shaded ? 45 : 3, 52, 42, SKIN_PLEDIT); + + g_signal_connect(playlistwin_close, "clicked", playlistwin_hide, NULL ); + + /* playlist list box */ + playlistwin_list = ui_skinned_playlist_new(SKINNED_WINDOW(playlistwin)->fixed, 12, 20, + playlistwin_get_width() - 31, + config.playlist_height - 58); + ui_skinned_playlist_set_font(aud_cfg->playlist_font); + + /* playlist list box slider */ + playlistwin_slider = ui_skinned_playlist_slider_new(SKINNED_WINDOW(playlistwin)->fixed, playlistwin_get_width() - 15, + 20, config.playlist_height - 58); + + /* track time (minute) */ + playlistwin_time_min = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 82, + config.playlist_height - 15, 15, FALSE, SKIN_TEXT); + g_signal_connect(playlistwin_time_min, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + /* track time (second) */ + playlistwin_time_sec = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 64, + config.playlist_height - 15, 10, FALSE, SKIN_TEXT); + g_signal_connect(playlistwin_time_sec, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + /* playlist information (current track length / total track length) */ + playlistwin_info = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 143, + config.playlist_height - 28, 90, FALSE, SKIN_TEXT); + + /* mini play control buttons at right bottom corner */ + + /* rewind button */ + playlistwin_srew = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_srew, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 144, + config.playlist_height - 16, 8, 7); + g_signal_connect(playlistwin_srew, "clicked", local_playlist_prev, NULL); + + /* play button */ + playlistwin_splay = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_splay, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 138, + config.playlist_height - 16, 10, 7); + g_signal_connect(playlistwin_splay, "clicked", mainwin_play_pushed, NULL); + + /* pause button */ + playlistwin_spause = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_spause, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 128, + config.playlist_height - 16, 10, 7); + g_signal_connect(playlistwin_spause, "clicked", audacious_drct_pause, NULL); + + /* stop button */ + playlistwin_sstop = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sstop, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 118, + config.playlist_height - 16, 9, 7); + g_signal_connect(playlistwin_sstop, "clicked", mainwin_stop_pushed, NULL); + + /* forward button */ + playlistwin_sfwd = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sfwd, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 109, + config.playlist_height - 16, 8, 7); + g_signal_connect(playlistwin_sfwd, "clicked", local_playlist_next, NULL); + + /* eject button */ + playlistwin_seject = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_seject, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 100, + config.playlist_height - 16, 9, 7); + g_signal_connect(playlistwin_seject, "clicked", mainwin_eject_pushed, NULL); + + playlistwin_sscroll_up = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sscroll_up, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 14, + config.playlist_height - 35, 8, 5); + g_signal_connect(playlistwin_sscroll_up, "clicked", playlistwin_scroll_up_pushed, NULL); + + playlistwin_sscroll_down = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sscroll_down, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 14, + config.playlist_height - 30, 8, 5); + g_signal_connect(playlistwin_sscroll_down, "clicked", playlistwin_scroll_down_pushed, NULL); + + ui_playlist_evlistener_init(); +} + +static void +selection_received(GtkWidget * widget, + GtkSelectionData * selection_data, gpointer data) +{ + if (selection_data->type == GDK_SELECTION_TYPE_STRING && + selection_data->length > 0) + aud_playlist_add_url(aud_playlist_get_active(), (gchar *) selection_data->data); +} + +static void +playlistwin_create_window(void) +{ + GdkPixbuf *icon; + + playlistwin = ui_skinned_window_new("playlist"); + gtk_window_set_title(GTK_WINDOW(playlistwin), _("Audacious Playlist Editor")); + gtk_window_set_role(GTK_WINDOW(playlistwin), "playlist"); + gtk_window_set_default_size(GTK_WINDOW(playlistwin), + playlistwin_get_width(), + playlistwin_get_height()); + gtk_window_set_resizable(GTK_WINDOW(playlistwin), TRUE); + playlistwin_set_geometry_hints(config.playlist_shaded); + + gtk_window_set_transient_for(GTK_WINDOW(playlistwin), + GTK_WINDOW(mainwin)); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(playlistwin), TRUE); + + icon = gdk_pixbuf_new_from_xpm_data((const gchar **) audacious_playlist_icon); + gtk_window_set_icon(GTK_WINDOW(playlistwin), icon); + g_object_unref(icon); + + if (config.playlist_x != -1 && config.save_window_position) + gtk_window_move(GTK_WINDOW(playlistwin), + config.playlist_x, config.playlist_y); + + gtk_widget_add_events(playlistwin, GDK_POINTER_MOTION_MASK | + GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | GDK_VISIBILITY_NOTIFY_MASK); + gtk_widget_realize(playlistwin); + + g_signal_connect(playlistwin, "delete_event", + G_CALLBACK(playlistwin_delete), NULL); + g_signal_connect(playlistwin, "button_press_event", + G_CALLBACK(playlistwin_press), NULL); + g_signal_connect(playlistwin, "button_release_event", + G_CALLBACK(playlistwin_release), NULL); + g_signal_connect(playlistwin, "scroll_event", + G_CALLBACK(playlistwin_scrolled), NULL); + g_signal_connect(playlistwin, "motion_notify_event", + G_CALLBACK(playlistwin_motion), NULL); + + aud_drag_dest_set(playlistwin); + + /* DnD stuff */ + g_signal_connect(playlistwin, "drag-leave", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-data-delete", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-end", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-drop", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-data-received", + G_CALLBACK(playlistwin_drag_data_received), NULL); + g_signal_connect(playlistwin, "drag-motion", + G_CALLBACK(playlistwin_drag_motion), NULL); + + g_signal_connect(playlistwin, "key_press_event", + G_CALLBACK(playlistwin_keypress), NULL); + g_signal_connect(playlistwin, "selection_received", + G_CALLBACK(selection_received), NULL); +} + +void +playlistwin_create(void) +{ + resize_mutex = g_mutex_new(); + playlistwin_create_window(); + + playlistwin_create_widgets(); + playlistwin_update_info(aud_playlist_get_active()); + + gtk_window_add_accel_group(GTK_WINDOW(playlistwin), ui_manager_get_accel_group()); +} + + +void +playlistwin_show(void) +{ + gtk_window_move(GTK_WINDOW(playlistwin), config.playlist_x, config.playlist_y); + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "show playlist editor" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE ); + + config.playlist_visible = TRUE; + UI_SKINNED_BUTTON(mainwin_pl)->inside = TRUE; + gtk_widget_queue_draw(mainwin_pl); + + playlistwin_set_toprow(0); + aud_playlist_check_pos_current(aud_playlist_get_active()); + + gtk_widget_show_all(playlistwin); + if (!config.playlist_shaded) + gtk_widget_hide(playlistwin_sinfo); + gtk_window_present(GTK_WINDOW(playlistwin)); +} + +void +playlistwin_hide(void) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "show playlist editor" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , FALSE ); + + gtk_widget_hide(playlistwin); + config.playlist_visible = FALSE; + UI_SKINNED_BUTTON(mainwin_pl)->inside = FALSE; + gtk_widget_queue_draw(mainwin_pl); + + if ( config.player_visible ) + { + gtk_window_present(GTK_WINDOW(mainwin)); + gtk_widget_grab_focus(mainwin); + } +} + +void action_playlist_track_info(void) +{ + playlistwin_fileinfo(); +} + +void action_queue_toggle(void) +{ + aud_playlist_queue(aud_playlist_get_active()); +} + +void action_playlist_sort_by_playlist_entry(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_PLAYLIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_track_number(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_TRACK); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_title(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_TITLE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_artist(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_ARTIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_full_path(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_PATH); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_date(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_DATE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_filename(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort(playlist, PLAYLIST_SORT_FILENAME); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_playlist_entry(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_PLAYLIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_track_number(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_TRACK); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_title(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_TITLE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_artist(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_ARTIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_full_path(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_PATH); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_date(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_DATE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_filename(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_sort_selected(playlist, PLAYLIST_SORT_FILENAME); + playlistwin_update_list(playlist); +} + +void action_playlist_randomize_list(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_random(playlist); + playlistwin_update_list(playlist); +} + +void action_playlist_reverse_list(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_reverse(playlist); + playlistwin_update_list(playlist); +} + +void +action_playlist_clear_queue(void) +{ + aud_playlist_clear_queue(aud_playlist_get_active()); +} + +void +action_playlist_remove_unavailable(void) +{ + aud_playlist_remove_dead_files(aud_playlist_get_active()); +} + +void +action_playlist_remove_dupes_by_title(void) +{ + aud_playlist_remove_duplicates(aud_playlist_get_active(), PLAYLIST_DUPS_TITLE); +} + +void +action_playlist_remove_dupes_by_filename(void) +{ + aud_playlist_remove_duplicates(aud_playlist_get_active(), PLAYLIST_DUPS_FILENAME); +} + +void +action_playlist_remove_dupes_by_full_path(void) +{ + aud_playlist_remove_duplicates(aud_playlist_get_active(), PLAYLIST_DUPS_PATH); +} + +void +action_playlist_remove_all(void) +{ + aud_playlist_clear(aud_playlist_get_active()); + + /* XXX -- should this really be coupled here? -nenolod */ + mainwin_clear_song_info(); +} + +void +action_playlist_remove_selected(void) +{ + aud_playlist_delete(aud_playlist_get_active(), FALSE); +} + +void +action_playlist_remove_unselected(void) +{ + aud_playlist_delete(aud_playlist_get_active(), TRUE); +} + +void +action_playlist_add_files(void) +{ +#if 0 + run_filebrowser(NO_PLAY_BUTTON); +#endif +} + +void +action_playlist_add_url(void) +{ + mainwin_show_add_url_window(); +} + +void +action_playlist_new( void ) +{ + Playlist *new_pl = aud_playlist_new(); + aud_playlist_add_playlist(new_pl); + aud_playlist_select_playlist(new_pl); +} + +void +action_playlist_prev( void ) +{ + aud_playlist_select_prev(); +} + +void +action_playlist_next( void ) +{ + aud_playlist_select_next(); +} + +void +action_playlist_delete( void ) +{ + aud_playlist_remove_playlist( aud_playlist_get_active() ); +} + +void +action_playlist_save_list(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + playlistwin_select_playlist_to_save(aud_playlist_get_current_name(playlist)); +} + +void +action_playlist_save_default_list(void) +{ +#if 0 + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_save(playlist, aud_paths[BMP_PATH_PLAYLIST_FILE]); +#endif +} + +void +action_playlist_load_list(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + playlistwin_select_playlist_to_load(aud_playlist_get_current_name(playlist)); +} + +void +action_playlist_refresh_list(void) +{ + Playlist *playlist = aud_playlist_get_active(); + + aud_playlist_read_info_selection(playlist); + playlistwin_update_list(playlist); +} + +void +action_open_list_manager(void) +{ +#if 0 + playlist_manager_ui_show(); +#endif +} + +void +action_playlist_search_and_select(void) +{ + playlistwin_select_search(); +} + +void +action_playlist_invert_selection(void) +{ + playlistwin_inverse_selection(); +} + +void +action_playlist_select_none(void) +{ + playlistwin_select_none(); +} + +void +action_playlist_select_all(void) +{ + playlistwin_select_all(); +} + + +static void +playlistwin_select_search_cbt_cb(GtkWidget *called_cbt, gpointer other_cbt) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(called_cbt)) == TRUE) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(other_cbt), FALSE); + return; +} + +static gboolean +playlistwin_select_search_kp_cb(GtkWidget *entry, GdkEventKey *event, + gpointer searchdlg_win) +{ + switch (event->keyval) + { + case GDK_Return: + if (gtk_im_context_filter_keypress (GTK_ENTRY (entry)->im_context, event)) { + GTK_ENTRY (entry)->need_im_reset = TRUE; + return TRUE; + } else { + gtk_dialog_response(GTK_DIALOG(searchdlg_win), GTK_RESPONSE_ACCEPT); + return TRUE; + } + default: + return FALSE; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_playlist.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,81 @@ +/* BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_PLAYLIST_H +#define AUDACIOUS_UI_PLAYLIST_H + +#include <glib.h> + +#include "ui_main.h" +#include <audacious/plugin.h> +#include "skins_cfg.h" + +#define PLAYLISTWIN_FRAME_TOP_HEIGHT 20 +#define PLAYLISTWIN_FRAME_BOTTOM_HEIGHT 38 +#define PLAYLISTWIN_FRAME_LEFT_WIDTH 12 +#define PLAYLISTWIN_FRAME_RIGHT_WIDTH 19 + +#define PLAYLISTWIN_MIN_WIDTH MAINWIN_WIDTH +#define PLAYLISTWIN_MIN_HEIGHT MAINWIN_HEIGHT +#define PLAYLISTWIN_WIDTH_SNAP 25 +#define PLAYLISTWIN_HEIGHT_SNAP 29 +#define PLAYLISTWIN_SHADED_HEIGHT MAINWIN_SHADED_HEIGHT +#define PLAYLISTWIN_WIDTH config.playlist_width +#define PLAYLISTWIN_HEIGHT \ + (config.playlist_shaded ? PLAYLISTWIN_SHADED_HEIGHT : config.playlist_height) + +#define PLAYLISTWIN_DEFAULT_WIDTH 275 +#define PLAYLISTWIN_DEFAULT_HEIGHT 232 +#define PLAYLISTWIN_DEFAULT_POS_X 295 +#define PLAYLISTWIN_DEFAULT_POS_Y 20 + +#define PLAYLISTWIN_DEFAULT_FONT "Sans Bold 8" + +gboolean playlistwin_is_shaded(void); +gint playlistwin_get_width(void); +gint playlistwin_get_height(void); +void playlistwin_update_list(Playlist *playlist); +gboolean playlistwin_item_visible(gint index); +gint playlistwin_get_toprow(void); +void playlistwin_set_toprow(gint top); +void playlistwin_set_shade_menu_cb(gboolean shaded); +void playlistwin_set_shade(gboolean shaded); +void playlistwin_shade_toggle(void); +void playlistwin_create(void); +void playlistwin_hide_timer(void); +void playlistwin_set_time(gint time, gint length, TimerMode mode); +void playlistwin_show(void); +void playlistwin_hide(void); +void playlistwin_scroll(gint num); +void playlistwin_scroll_up_pushed(void); +void playlistwin_scroll_down_pushed(void); +void playlistwin_select_playlist_to_load(const gchar * default_filename); +void playlistwin_set_sinfo_font(gchar *font); +void playlistwin_set_sinfo_scroll(gboolean scroll); +gint playlistwin_list_get_visible_count(void); +gint playlistwin_list_get_first(void); + +extern GtkWidget *playlistwin; + +extern gboolean playlistwin_focus; + +#endif /* AUDACIOUS_UI_PLAYLIST_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_playlist_evlisteners.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,57 @@ +/* + * Audacious + * Copyright (c) 2006-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_playlist_evlisteners.h" + +#include <glib.h> +#if 0 +#include "hook.h" +#include "playlist.h" +#endif +#include "ui_playlist.h" +#if 0 +#include "ui_playlist_manager.h" +#endif +static void +ui_playlist_evlistener_playlist_update(gpointer hook_data, gpointer user_data) +{ + Playlist *playlist = (Playlist *) hook_data; + if (playlist != NULL) + playlistwin_update_list(playlist); +#if 0 + playlist_manager_update(); +#endif +} + +static void +ui_playlist_evlistener_playlistwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + playlistwin_show(); + else + playlistwin_hide(); +} + +void ui_playlist_evlistener_init(void) +{ + aud_hook_associate("playlist update", ui_playlist_evlistener_playlist_update, NULL); + aud_hook_associate("playlistwin show", ui_playlist_evlistener_playlistwin_show, NULL); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_playlist_evlisteners.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,26 @@ +/* + * Audacious + * Copyright (c) 2006-2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H +#define AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H + +void ui_playlist_evlistener_init(void); + +#endif /* AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skin.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,2062 @@ +/* Audacious + * Copyright (C) 2005-2007 Audacious development team. + * + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +/*#define AUD_DEBUG*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* TODO: enforce default sizes! */ + +#include <glib.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "plugin.h" + +#include <audacious/plugin.h> +#include "ui_skin.h" +#include "util.h" +#include "ui_main.h" +#include "ui_equalizer.h" +#include "ui_playlist.h" +#if 0 +#include "ui_skinselector.h" +#endif +#include "debug.h" + +#include "platform/smartinclude.h" + +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_number.h" +#include "ui_skinned_horizontal_slider.h" +#include "ui_skinned_playstatus.h" + +#define EXTENSION_TARGETS 7 + +static gchar *ext_targets[EXTENSION_TARGETS] = +{ "bmp", "xpm", "png", "svg", "gif", "jpg", "jpeg" }; + +struct _SkinPixmapIdMapping { + SkinPixmapId id; + const gchar *name; + const gchar *alt_name; + gint width, height; +}; + +struct _SkinMaskInfo { + gint width, height; + gchar *inistr; +}; +/* I know, it's not nice to copy'n'paste stuff, but I wanted it to + be atleast parially working, before dealing with such things */ + +typedef struct { + const gchar *to_match; + gchar *match; + gboolean found; +} FindFileContext; + +typedef struct _SkinPixmapIdMapping SkinPixmapIdMapping; +typedef struct _SkinMaskInfo SkinMaskInfo; + + +Skin *aud_active_skin = NULL; + +static gint skin_current_num; + +static SkinMaskInfo skin_mask_info[] = { + {275, 116, "Normal"}, + {275, 16, "WindowShade"}, + {275, 116, "Equalizer"}, + {275, 16, "EqualizerWS"} +}; + +static SkinPixmapIdMapping skin_pixmap_id_map[] = { + {SKIN_MAIN, "main", NULL, 0, 0}, + {SKIN_CBUTTONS, "cbuttons", NULL, 0, 0}, + {SKIN_SHUFREP, "shufrep", NULL, 0, 0}, + {SKIN_TEXT, "text", NULL, 0, 0}, + {SKIN_TITLEBAR, "titlebar", NULL, 0, 0}, + {SKIN_VOLUME, "volume", NULL, 0, 0}, + {SKIN_BALANCE, "balance", "volume", 0, 0}, + {SKIN_MONOSTEREO, "monoster", NULL, 0, 0}, + {SKIN_PLAYPAUSE, "playpaus", NULL, 0, 0}, + {SKIN_NUMBERS, "nums_ex", "numbers", 0, 0}, + {SKIN_POSBAR, "posbar", NULL, 0, 0}, + {SKIN_EQMAIN, "eqmain", NULL, 0, 0}, + {SKIN_PLEDIT, "pledit", NULL, 0, 0}, + {SKIN_EQ_EX, "eq_ex", NULL, 0, 0} +}; + +static guint skin_pixmap_id_map_size = G_N_ELEMENTS(skin_pixmap_id_map); + +static const guchar skin_default_viscolor[24][3] = { + {9, 34, 53}, + {10, 18, 26}, + {0, 54, 108}, + {0, 58, 116}, + {0, 62, 124}, + {0, 66, 132}, + {0, 70, 140}, + {0, 74, 148}, + {0, 78, 156}, + {0, 82, 164}, + {0, 86, 172}, + {0, 92, 184}, + {0, 98, 196}, + {0, 104, 208}, + {0, 110, 220}, + {0, 116, 232}, + {0, 122, 244}, + {0, 128, 255}, + {0, 128, 255}, + {0, 104, 208}, + {0, 80, 160}, + {0, 56, 112}, + {0, 32, 64}, + {200, 200, 200} +}; + +static gchar *original_gtk_theme = NULL; + +static GdkBitmap *skin_create_transparent_mask(const gchar *, + const gchar *, + const gchar *, + GdkWindow *, + gint, gint, gboolean); + +static void skin_set_default_vis_color(Skin * skin); + +void +skin_lock(Skin * skin) +{ + g_mutex_lock(skin->lock); +} + +void +skin_unlock(Skin * skin) +{ + g_mutex_unlock(skin->lock); +} + +gboolean +aud_active_skin_reload(void) +{ + AUDDBG("\n"); + return aud_active_skin_load(aud_active_skin->path); +} + +gboolean +aud_active_skin_load(const gchar * path) +{ + AUDDBG("%s\n", path); + g_return_val_if_fail(aud_active_skin != NULL, FALSE); + + if (!skin_load(aud_active_skin, path)) { + AUDDBG("loading failed\n"); + return FALSE; + } + + ui_skinned_window_draw_all(mainwin); + ui_skinned_window_draw_all(equalizerwin); + ui_skinned_window_draw_all(playlistwin); + + playlistwin_update_list(aud_playlist_get_active()); + + SkinPixmap *pixmap; + pixmap = &aud_active_skin->pixmaps[SKIN_POSBAR]; + /* last 59 pixels of SKIN_POSBAR are knobs (normal and selected) */ + gtk_widget_set_size_request(mainwin_position, pixmap->width - 59, pixmap->height); + + return TRUE; +} + +void +skin_pixmap_free(SkinPixmap * p) +{ + g_return_if_fail(p != NULL); + g_return_if_fail(p->pixbuf != NULL); + + g_object_unref(p->pixbuf); + p->pixbuf = NULL; +} + +Skin * +skin_new(void) +{ + Skin *skin; + skin = g_new0(Skin, 1); + skin->lock = g_mutex_new(); + return skin; +} + +/** + * Frees the data associated for skin. + * + * Does not free skin itself or lock variable so that the skin can immediately + * populated with new skin data if needed. + */ +void +skin_free(Skin * skin) +{ + gint i; + + g_return_if_fail(skin != NULL); + + for (i = 0; i < SKIN_PIXMAP_COUNT; i++) + skin_pixmap_free(&skin->pixmaps[i]); + + for (i = 0; i < SKIN_MASK_COUNT; i++) { + if (skin->masks[i]) + g_object_unref(skin->masks[i]); + if (skin->scaled_masks[i]) + g_object_unref(skin->scaled_masks[i]); + + skin->masks[i] = NULL; + skin->scaled_masks[i] = NULL; + } + + for (i = 0; i < SKIN_COLOR_COUNT; i++) { + if (skin->colors[i]) + g_free(skin->colors[i]); + + skin->colors[i] = NULL; + } + + g_free(skin->path); + skin->path = NULL; + + skin_set_default_vis_color(skin); +} + +void +skin_destroy(Skin * skin) +{ + g_return_if_fail(skin != NULL); + skin_free(skin); + g_mutex_free(skin->lock); + g_free(skin); +} + +const SkinPixmapIdMapping * +skin_pixmap_id_lookup(guint id) +{ + guint i; + + for (i = 0; i < skin_pixmap_id_map_size; i++) { + if (id == skin_pixmap_id_map[i].id) { + return &skin_pixmap_id_map[i]; + } + } + + return NULL; +} + +const gchar * +skin_pixmap_id_to_name(SkinPixmapId id) +{ + guint i; + + for (i = 0; i < skin_pixmap_id_map_size; i++) { + if (id == skin_pixmap_id_map[i].id) + return skin_pixmap_id_map[i].name; + } + return NULL; +} + +static void +skin_set_default_vis_color(Skin * skin) +{ + memcpy(skin->vis_color, skin_default_viscolor, + sizeof(skin_default_viscolor)); +} + +/* + * I have rewritten this to take an array of possible targets, + * once we find a matching target we now return, instead of loop + * recursively. This allows for us to support many possible format + * targets for our skinning engine than just the original winamp + * formats. + * + * -- nenolod, 16 January 2006 + */ +gchar * +skin_pixmap_locate(const gchar * dirname, gchar ** basenames) +{ + gchar *filename; + gint i; + + for (i = 0; basenames[i]; i++) + if (!(filename = find_path_recursively(dirname, basenames[i]))) + g_free(filename); + else + return filename; + + /* can't find any targets -- sorry */ + return NULL; +} + +/** + * Creates possible file names for a pixmap. + * + * Basically this makes list of all possible file names that pixmap data + * can be found from by using the static ext_targets variable to get all + * possible extensions that pixmap file might have. + */ +static gchar ** +skin_pixmap_create_basenames(const SkinPixmapIdMapping * pixmap_id_mapping) +{ + gchar **basenames = g_malloc0(sizeof(gchar*) * (EXTENSION_TARGETS * 2 + 1)); + gint i, y; + + // Create list of all possible image formats that can be loaded + for (i = 0, y = 0; i < EXTENSION_TARGETS; i++, y++) + { + basenames[y] = + g_strdup_printf("%s.%s", pixmap_id_mapping->name, ext_targets[i]); + + if (pixmap_id_mapping->alt_name) + basenames[++y] = + g_strdup_printf("%s.%s", pixmap_id_mapping->alt_name, + ext_targets[i]); + } + + return basenames; +} + +/** + * Frees the data allocated by skin_pixmap_create_basenames + */ +static void +skin_pixmap_free_basenames(gchar ** basenames) +{ + int i; + for (i = 0; basenames[i] != NULL; i++) + { + g_free(basenames[i]); + basenames[i] = NULL; + } + g_free(basenames); +} + +/** + * Locates a pixmap file for skin. + */ +static gchar * +skin_pixmap_locate_basenames(const Skin * skin, + const SkinPixmapIdMapping * pixmap_id_mapping, + const gchar * path_p) +{ + gchar *filename = NULL; + const gchar *path = path_p ? path_p : skin->path; + gchar **basenames = skin_pixmap_create_basenames(pixmap_id_mapping); + + filename = skin_pixmap_locate(path, basenames); + + skin_pixmap_free_basenames(basenames); + + return filename; +} + + +static gboolean +skin_load_pixmap_id(Skin * skin, SkinPixmapId id, const gchar * path_p) +{ + const SkinPixmapIdMapping *pixmap_id_mapping; + gchar *filename; + SkinPixmap *pm = NULL; + + g_return_val_if_fail(skin != NULL, FALSE); + g_return_val_if_fail(id < SKIN_PIXMAP_COUNT, FALSE); + + pixmap_id_mapping = skin_pixmap_id_lookup(id); + g_return_val_if_fail(pixmap_id_mapping != NULL, FALSE); + + filename = skin_pixmap_locate_basenames(skin, pixmap_id_mapping, path_p); + + if (filename == NULL) + return FALSE; + + AUDDBG("loaded %s\n", filename); + + pm = &skin->pixmaps[id]; + GdkPixbuf *pix = gdk_pixbuf_new_from_file(filename, NULL); + pm->pixbuf = audacious_create_colorized_pixbuf(pix, config.colorize_r, aud_cfg->colorize_g, aud_cfg->colorize_b); + g_object_unref(pix); + pm->width = gdk_pixbuf_get_width(pm->pixbuf); + pm->height = gdk_pixbuf_get_height(pm->pixbuf); + pm->current_width = pm->width; + pm->current_height = pm->height; + + g_free(filename); + + return TRUE; +} + +void +skin_mask_create(Skin * skin, + const gchar * path, + gint id, + GdkWindow * window) +{ + skin->masks[id] = + skin_create_transparent_mask(path, "region.txt", + skin_mask_info[id].inistr, window, + skin_mask_info[id].width, + skin_mask_info[id].height, FALSE); + + skin->scaled_masks[id] = + skin_create_transparent_mask(path, "region.txt", + skin_mask_info[id].inistr, window, + skin_mask_info[id].width * 2, + skin_mask_info[id].height * 2, TRUE); +} + +static GdkBitmap * +create_default_mask(GdkWindow * parent, gint w, gint h) +{ + GdkBitmap *ret; + GdkGC *gc; + GdkColor pattern; + + ret = gdk_pixmap_new(parent, w, h, 1); + gc = gdk_gc_new(ret); + pattern.pixel = 1; + gdk_gc_set_foreground(gc, &pattern); + gdk_draw_rectangle(ret, gc, TRUE, 0, 0, w, h); + g_object_unref(gc); + + return ret; +} + +static void +skin_query_color(GdkColormap * cm, GdkColor * c) +{ +#ifdef GDK_WINDOWING_X11 + XColor xc = { 0,0,0,0,0,0 }; + + xc.pixel = c->pixel; + XQueryColor(GDK_COLORMAP_XDISPLAY(cm), GDK_COLORMAP_XCOLORMAP(cm), &xc); + c->red = xc.red; + c->green = xc.green; + c->blue = xc.blue; +#else + /* do nothing. see what breaks? */ +#endif +} + +static glong +skin_calc_luminance(GdkColor * c) +{ + return (0.212671 * c->red + 0.715160 * c->green + 0.072169 * c->blue); +} + +static void +skin_get_textcolors(GdkPixbuf * pix, GdkColor * bgc, GdkColor * fgc) +{ + /* + * Try to extract reasonable background and foreground colors + * from the font pixmap + */ + + GdkImage *gi; + GdkColormap *cm; + gint i; + + g_return_if_fail(pix != NULL); + + GdkPixmap *text = gdk_pixmap_new(NULL, gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), gdk_rgb_get_visual()->depth); + gdk_draw_pixbuf(text, NULL, pix, 0, 0, 0, 0, gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), + GDK_RGB_DITHER_NONE, 0, 0); + /* Get the first line of text */ + gi = gdk_drawable_get_image(text, 0, 0, 152, 6); + cm = gdk_colormap_get_system(); + + for (i = 0; i < 6; i++) { + GdkColor c; + gint x; + glong d, max_d; + + /* Get a pixel from the middle of the space character */ + bgc[i].pixel = gdk_image_get_pixel(gi, 151, i); + skin_query_color(cm, &bgc[i]); + + max_d = 0; + for (x = 1; x < 150; x++) { + c.pixel = gdk_image_get_pixel(gi, x, i); + skin_query_color(cm, &c); + + d = labs(skin_calc_luminance(&c) - skin_calc_luminance(&bgc[i])); + if (d > max_d) { + memcpy(&fgc[i], &c, sizeof(GdkColor)); + max_d = d; + } + } + } + g_object_unref(gi); + g_object_unref(text); +} + +gboolean +init_skins(const gchar * path) +{ + aud_active_skin = skin_new(); + + skin_parse_hints(aud_active_skin, NULL); + + /* create the windows if they haven't been created yet, needed for bootstrapping */ + if (mainwin == NULL) + { + mainwin_create(); + equalizerwin_create(); + playlistwin_create(); + } + + if (!aud_active_skin_load(path)) { + if (path != NULL) + AUDDBG("Unable to load skin (%s), trying default...\n", path); + else + AUDDBG("Skin not defined: trying default...\n"); + + /* can't load configured skin, retry with default */ + if (!aud_active_skin_load(BMP_DEFAULT_SKIN_PATH)) { + AUDDBG("Unable to load default skin (%s)! Giving up.\n", + BMP_DEFAULT_SKIN_PATH); + return FALSE; + } + } +#if 0 + if (config.random_skin_on_play) + skinlist_update(); +#endif + return TRUE; +} + +void cleanup_skins() +{ + skin_destroy(aud_active_skin); + aud_active_skin = NULL; +} + + +/* + * Opens and parses a skin's hints file. + * Hints files are somewhat like "scripts" in Winamp3/5. + * We'll probably add scripts to it next. + */ +void +skin_parse_hints(Skin * skin, gchar *path_p) +{ + gchar *filename, *tmp; + INIFile *inifile; + + path_p = path_p ? path_p : skin->path; + + skin->properties.mainwin_othertext = FALSE; + skin->properties.mainwin_vis_x = 24; + skin->properties.mainwin_vis_y = 43; + skin->properties.mainwin_vis_width = 76; + skin->properties.mainwin_text_x = 112; + skin->properties.mainwin_text_y = 27; + skin->properties.mainwin_text_width = 153; + skin->properties.mainwin_infobar_x = 112; + skin->properties.mainwin_infobar_y = 43; + skin->properties.mainwin_number_0_x = 36; + skin->properties.mainwin_number_0_y = 26; + skin->properties.mainwin_number_1_x = 48; + skin->properties.mainwin_number_1_y = 26; + skin->properties.mainwin_number_2_x = 60; + skin->properties.mainwin_number_2_y = 26; + skin->properties.mainwin_number_3_x = 78; + skin->properties.mainwin_number_3_y = 26; + skin->properties.mainwin_number_4_x = 90; + skin->properties.mainwin_number_4_y = 26; + skin->properties.mainwin_playstatus_x = 24; + skin->properties.mainwin_playstatus_y = 28; + skin->properties.mainwin_menurow_visible = TRUE; + skin->properties.mainwin_volume_x = 107; + skin->properties.mainwin_volume_y = 57; + skin->properties.mainwin_balance_x = 177; + skin->properties.mainwin_balance_y = 57; + skin->properties.mainwin_position_x = 16; + skin->properties.mainwin_position_y = 72; + skin->properties.mainwin_othertext_is_status = FALSE; + skin->properties.mainwin_othertext_visible = skin->properties.mainwin_othertext; + skin->properties.mainwin_text_visible = TRUE; + skin->properties.mainwin_vis_visible = TRUE; + skin->properties.mainwin_previous_x = 16; + skin->properties.mainwin_previous_y = 88; + skin->properties.mainwin_play_x = 39; + skin->properties.mainwin_play_y = 88; + skin->properties.mainwin_pause_x = 62; + skin->properties.mainwin_pause_y = 88; + skin->properties.mainwin_stop_x = 85; + skin->properties.mainwin_stop_y = 88; + skin->properties.mainwin_next_x = 108; + skin->properties.mainwin_next_y = 88; + skin->properties.mainwin_eject_x = 136; + skin->properties.mainwin_eject_y = 89; + skin->properties.mainwin_width = 275; + skin_mask_info[0].width = skin->properties.mainwin_width; + skin->properties.mainwin_height = 116; + skin_mask_info[0].height = skin->properties.mainwin_height; + skin->properties.mainwin_about_x = 247; + skin->properties.mainwin_about_y = 83; + skin->properties.mainwin_shuffle_x = 164; + skin->properties.mainwin_shuffle_y = 89; + skin->properties.mainwin_repeat_x = 210; + skin->properties.mainwin_repeat_y = 89; + skin->properties.mainwin_eqbutton_x = 219; + skin->properties.mainwin_eqbutton_y = 58; + skin->properties.mainwin_plbutton_x = 242; + skin->properties.mainwin_plbutton_y = 58; + skin->properties.textbox_bitmap_font_width = 5; + skin->properties.textbox_bitmap_font_height = 6; + skin->properties.mainwin_minimize_x = 244; + skin->properties.mainwin_minimize_y = 3; + skin->properties.mainwin_shade_x = 254; + skin->properties.mainwin_shade_y = 3; + skin->properties.mainwin_close_x = 264; + skin->properties.mainwin_close_y = 3; + + if (path_p == NULL) + return; + + filename = find_file_recursively(path_p, "skin.hints"); + + if (filename == NULL) + return; + + inifile = aud_open_ini_file(filename); + if (!inifile) + return; + + tmp = aud_read_ini_string(inifile, "skin", "mainwinOthertext"); + + if (tmp != NULL) + { + skin->properties.mainwin_othertext = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinVisX"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinVisY"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinVisWidth"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_width = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinTextX"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinTextY"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinTextWidth"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_width = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinInfoBarX"); + + if (tmp != NULL) + { + skin->properties.mainwin_infobar_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinInfoBarY"); + + if (tmp != NULL) + { + skin->properties.mainwin_infobar_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber0X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_0_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber0Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_0_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber1X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_1_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber1Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_1_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber2X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_2_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber2Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_2_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber3X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_3_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber3Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_3_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber4X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_4_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNumber4Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_4_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPlayStatusX"); + + if (tmp != NULL) + { + skin->properties.mainwin_playstatus_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPlayStatusY"); + + if (tmp != NULL) + { + skin->properties.mainwin_playstatus_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinMenurowVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_menurow_visible = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinVolumeX"); + + if (tmp != NULL) + { + skin->properties.mainwin_volume_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinVolumeY"); + + if (tmp != NULL) + { + skin->properties.mainwin_volume_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinBalanceX"); + + if (tmp != NULL) + { + skin->properties.mainwin_balance_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinBalanceY"); + + if (tmp != NULL) + { + skin->properties.mainwin_balance_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPositionX"); + + if (tmp != NULL) + { + skin->properties.mainwin_position_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPositionY"); + + if (tmp != NULL) + { + skin->properties.mainwin_position_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinOthertextIsStatus"); + + if (tmp != NULL) + { + skin->properties.mainwin_othertext_is_status = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinOthertextVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_othertext_visible = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinTextVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_visible = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinVisVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_visible = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPreviousX"); + + if (tmp != NULL) + { + skin->properties.mainwin_previous_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPreviousY"); + + if (tmp != NULL) + { + skin->properties.mainwin_previous_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPlayX"); + + if (tmp != NULL) + { + skin->properties.mainwin_play_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPlayY"); + + if (tmp != NULL) + { + skin->properties.mainwin_play_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPauseX"); + + if (tmp != NULL) + { + skin->properties.mainwin_pause_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPauseY"); + + if (tmp != NULL) + { + skin->properties.mainwin_pause_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinStopX"); + + if (tmp != NULL) + { + skin->properties.mainwin_stop_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinStopY"); + + if (tmp != NULL) + { + skin->properties.mainwin_stop_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNextX"); + + if (tmp != NULL) + { + skin->properties.mainwin_next_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinNextY"); + + if (tmp != NULL) + { + skin->properties.mainwin_next_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinEjectX"); + + if (tmp != NULL) + { + skin->properties.mainwin_eject_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinEjectY"); + + if (tmp != NULL) + { + skin->properties.mainwin_eject_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinWidth"); + + if (tmp != NULL) + { + skin->properties.mainwin_width = atoi(tmp); + g_free(tmp); + } + + skin_mask_info[0].width = skin->properties.mainwin_width; + + tmp = aud_read_ini_string(inifile, "skin", "mainwinHeight"); + + if (tmp != NULL) + { + skin->properties.mainwin_height = atoi(tmp); + g_free(tmp); + } + + skin_mask_info[0].height = skin->properties.mainwin_height; + + tmp = aud_read_ini_string(inifile, "skin", "mainwinAboutX"); + + if (tmp != NULL) + { + skin->properties.mainwin_about_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinAboutY"); + + if (tmp != NULL) + { + skin->properties.mainwin_about_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinShuffleX"); + + if (tmp != NULL) + { + skin->properties.mainwin_shuffle_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinShuffleY"); + + if (tmp != NULL) + { + skin->properties.mainwin_shuffle_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinRepeatX"); + + if (tmp != NULL) + { + skin->properties.mainwin_repeat_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinRepeatY"); + + if (tmp != NULL) + { + skin->properties.mainwin_repeat_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinEQButtonX"); + + if (tmp != NULL) + { + skin->properties.mainwin_eqbutton_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinEQButtonY"); + + if (tmp != NULL) + { + skin->properties.mainwin_eqbutton_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPLButtonX"); + + if (tmp != NULL) + { + skin->properties.mainwin_plbutton_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinPLButtonY"); + + if (tmp != NULL) + { + skin->properties.mainwin_plbutton_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "textboxBitmapFontWidth"); + + if (tmp != NULL) + { + skin->properties.textbox_bitmap_font_width = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "textboxBitmapFontHeight"); + + if (tmp != NULL) + { + skin->properties.textbox_bitmap_font_height = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinMinimizeX"); + + if (tmp != NULL) + { + skin->properties.mainwin_minimize_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinMinimizeY"); + + if (tmp != NULL) + { + skin->properties.mainwin_minimize_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinShadeX"); + + if (tmp != NULL) + { + skin->properties.mainwin_shade_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinShadeY"); + + if (tmp != NULL) + { + skin->properties.mainwin_shade_y = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinCloseX"); + + if (tmp != NULL) + { + skin->properties.mainwin_close_x = atoi(tmp); + g_free(tmp); + } + + tmp = aud_read_ini_string(inifile, "skin", "mainwinCloseY"); + + if (tmp != NULL) + { + skin->properties.mainwin_close_y = atoi(tmp); + g_free(tmp); + } + + if (filename != NULL) + g_free(filename); + + aud_close_ini_file(inifile); +} + +static guint +hex_chars_to_int(gchar hi, gchar lo) +{ + /* + * Converts a value in the range 0x00-0xFF + * to a integer in the range 0-65535 + */ + gchar str[3]; + + str[0] = hi; + str[1] = lo; + str[2] = 0; + + return (CLAMP(strtol(str, NULL, 16), 0, 0xFF) << 8); +} + +static GdkColor * +skin_load_color(INIFile *inifile, + const gchar * section, const gchar * key, + gchar * default_hex) +{ + gchar *value; + GdkColor *color = NULL; + + if (inifile || default_hex) { + if (inifile) { + value = aud_read_ini_string(inifile, section, key); + if (value == NULL) { + value = g_strdup(default_hex); + } + } else { + value = g_strdup(default_hex); + } + if (value) { + gchar *ptr = value; + gint len; + + color = g_new0(GdkColor, 1); + g_strstrip(value); + + if (value[0] == '#') + ptr++; + len = strlen(ptr); + /* + * The handling of incomplete values is done this way + * to maximize winamp compatibility + */ + if (len >= 6) { + color->red = hex_chars_to_int(*ptr, *(ptr + 1)); + ptr += 2; + } + if (len >= 4) { + color->green = hex_chars_to_int(*ptr, *(ptr + 1)); + ptr += 2; + } + if (len >= 2) + color->blue = hex_chars_to_int(*ptr, *(ptr + 1)); + + g_free(value); + } + } + return color; +} + + + +GdkBitmap * +skin_create_transparent_mask(const gchar * path, + const gchar * file, + const gchar * section, + GdkWindow * window, + gint width, + gint height, gboolean scale) +{ + GdkBitmap *mask = NULL; + GdkGC *gc = NULL; + GdkColor pattern; + GdkPoint *gpoints; + + gchar *filename = NULL; + INIFile *inifile = NULL; + gboolean created_mask = FALSE; + GArray *num, *point; + guint i, j; + gint k; + + if (path) + filename = find_file_recursively(path, file); + + /* filename will be null if path wasn't set */ + if (!filename) + return create_default_mask(window, width, height); + + inifile = aud_open_ini_file(filename); + + if ((num = aud_read_ini_array(inifile, section, "NumPoints")) == NULL) { + g_free(filename); + aud_close_ini_file(inifile); + return NULL; + } + + if ((point = aud_read_ini_array(inifile, section, "PointList")) == NULL) { + g_array_free(num, TRUE); + g_free(filename); + aud_close_ini_file(inifile); + return NULL; + } + + aud_close_ini_file(inifile); + + mask = gdk_pixmap_new(window, width, height, 1); + gc = gdk_gc_new(mask); + + pattern.pixel = 0; + gdk_gc_set_foreground(gc, &pattern); + gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height); + pattern.pixel = 1; + gdk_gc_set_foreground(gc, &pattern); + + j = 0; + for (i = 0; i < num->len; i++) { + if ((int)(point->len - j) >= (g_array_index(num, gint, i) * 2)) { + created_mask = TRUE; + gpoints = g_new(GdkPoint, g_array_index(num, gint, i)); + for (k = 0; k < g_array_index(num, gint, i); k++) { + gpoints[k].x = + g_array_index(point, gint, j + k * 2) * (scale ? config.scale_factor : 1 ); + gpoints[k].y = + g_array_index(point, gint, + j + k * 2 + 1) * (scale ? config.scale_factor : 1); + } + j += k * 2; + gdk_draw_polygon(mask, gc, TRUE, gpoints, + g_array_index(num, gint, i)); + g_free(gpoints); + } + } + g_array_free(num, TRUE); + g_array_free(point, TRUE); + g_free(filename); + + if (!created_mask) + gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height); + + g_object_unref(gc); + + return mask; +} + +void +skin_load_viscolor(Skin * skin, const gchar * path, const gchar * basename) +{ +#if 0 + VFSFile *file; + gint i, c; + gchar line[256], *filename; + GArray *a; + + g_return_if_fail(skin != NULL); + g_return_if_fail(path != NULL); + g_return_if_fail(basename != NULL); + + skin_set_default_vis_color(skin); + + filename = find_file_recursively(path, basename); + if (!filename) + return; + + if (!(file = vfs_fopen(filename, "r"))) { + g_free(filename); + return; + } + + g_free(filename); + + for (i = 0; i < 24; i++) { + if (vfs_fgets(line, 255, file)) { + a = string_to_garray(line); + if (a->len > 2) { + for (c = 0; c < 3; c++) + skin->vis_color[i][c] = g_array_index(a, gint, c); + } + g_array_free(a, TRUE); + } + else + break; + } + + vfs_fclose(file); +#endif +} + +static void +skin_numbers_generate_dash(Skin * skin) +{ + GdkPixbuf *pixbuf; + SkinPixmap *numbers; + + g_return_if_fail(skin != NULL); + + numbers = &skin->pixmaps[SKIN_NUMBERS]; + if (!numbers->pixbuf || numbers->current_width < 99) + return; + + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, + 108, numbers->current_height); + + skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 0, 0, 0, 0, 99, numbers->current_height); + skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 90, 0, 99, 0, 9, numbers->current_height); + skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 20, 6, 101, 6, 5, 1); + + g_object_unref(numbers->pixbuf); + + numbers->pixbuf = pixbuf; + numbers->current_width = 108; + numbers->width = 108; +} + +static gboolean +skin_load_pixmaps(Skin * skin, const gchar * path) +{ + GdkPixbuf *text_pb; + guint i; + gchar *filename; + INIFile *inifile; + + if(!skin) return FALSE; + if(!path) return FALSE; + + AUDDBG("Loading pixmaps in %s\n", path); + + for (i = 0; i < SKIN_PIXMAP_COUNT; i++) + if (!skin_load_pixmap_id(skin, i, path) && !config.allow_broken_skins) + return FALSE; + + text_pb = skin->pixmaps[SKIN_TEXT].pixbuf; + + if (text_pb) + skin_get_textcolors(text_pb, skin->textbg, skin->textfg); + + if (skin->pixmaps[SKIN_NUMBERS].pixbuf && + skin->pixmaps[SKIN_NUMBERS].width < 108 ) + skin_numbers_generate_dash(skin); + + filename = find_file_recursively(path, "pledit.txt"); + inifile = aud_open_ini_file(filename); + + skin->colors[SKIN_PLEDIT_NORMAL] = + skin_load_color(inifile, "Text", "Normal", "#2499ff"); + skin->colors[SKIN_PLEDIT_CURRENT] = + skin_load_color(inifile, "Text", "Current", "#ffeeff"); + skin->colors[SKIN_PLEDIT_NORMALBG] = + skin_load_color(inifile, "Text", "NormalBG", "#0a120a"); + skin->colors[SKIN_PLEDIT_SELECTEDBG] = + skin_load_color(inifile, "Text", "SelectedBG", "#0a124a"); + + if (inifile) + aud_close_ini_file(inifile); + + if (filename) + g_free(filename); + + skin_mask_create(skin, path, SKIN_MASK_MAIN, mainwin->window); + skin_mask_create(skin, path, SKIN_MASK_MAIN_SHADE, mainwin->window); + + skin_mask_create(skin, path, SKIN_MASK_EQ, equalizerwin->window); + skin_mask_create(skin, path, SKIN_MASK_EQ_SHADE, equalizerwin->window); +#if 0 + skin_load_viscolor(skin, path, "viscolor.txt"); +#endif + return TRUE; +} + +static void +skin_set_gtk_theme(GtkSettings * settings, Skin * skin) +{ + if (original_gtk_theme == NULL) + g_object_get(settings, "gtk-theme-name", &original_gtk_theme, NULL); + + /* the way GTK does things can be very broken. --nenolod */ + + gchar *tmp = g_strdup_printf("%s/.themes/aud-%s", g_get_home_dir(), + basename(skin->path)); + + gchar *troot = g_strdup_printf("%s/.themes", g_get_home_dir()); + g_mkdir_with_parents(troot, 0755); + g_free(troot); + + symlink(skin->path, tmp); + gtk_settings_set_string_property(settings, "gtk-theme-name", + basename(tmp), "audacious"); + g_free(tmp); +} + +/** + * Checks if all pixmap files exist that skin needs. + */ +static gboolean +skin_check_pixmaps(const Skin * skin, const gchar * skin_path) +{ + guint i; + for (i = 0; i < SKIN_PIXMAP_COUNT; i++) + { + gchar *filename = skin_pixmap_locate_basenames(skin, + skin_pixmap_id_lookup(i), + skin_path); + if (!filename) + return FALSE; + g_free(filename); + } + return TRUE; +} + +static gboolean +skin_load_nolock(Skin * skin, const gchar * path, gboolean force) +{ + GtkSettings *settings; + gchar *gtkrcpath; + gchar *newpath, *skin_path; + int archive = 0; + + AUDDBG("Attempt to load skin \"%s\"\n", path); + + g_return_val_if_fail(skin != NULL, FALSE); + g_return_val_if_fail(path != NULL, FALSE); + REQUIRE_LOCK(skin->lock); + + if (!g_file_test(path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_DIR)) + return FALSE; + + if(force) AUDDBG("reloading forced!\n"); + if (!force && skin->path && !strcmp(skin->path, path)) { + AUDDBG("skin %s already loaded\n", path); + return FALSE; + } + + if (file_is_archive(path)) { + AUDDBG("Attempt to load archive\n"); + if (!(skin_path = archive_decompress(path))) { + AUDDBG("Unable to extract skin archive (%s)\n", path); + return FALSE; + } + archive = 1; + } else { + skin_path = g_strdup(path); + } + + // Check if skin path has all necessary files. + if (!config.allow_broken_skins && !skin_check_pixmaps(skin, skin_path)) { + if(archive) del_directory(skin_path); + g_free(skin_path); + AUDDBG("Skin path (%s) doesn't have all wanted pixmaps\n", skin_path); + return FALSE; + } + + // skin_free() frees skin->path and variable path can actually be skin->path + // and we want to get the path before possibly freeing it. + newpath = g_strdup(path); + skin_free(skin); + skin->path = newpath; + + memset(&(skin->properties), 0, sizeof(SkinProperties)); /* do it only if all tests above passed! --asphyx */ + + skin_current_num++; + + /* Parse the hints for this skin. */ + skin_parse_hints(skin, skin_path); + + if (!skin_load_pixmaps(skin, skin_path)) { + if(archive) del_directory(skin_path); + g_free(skin_path); + AUDDBG("Skin loading failed\n"); + return FALSE; + } + + /* restore gtk theme if changed by previous skin */ + settings = gtk_settings_get_default(); + + if (original_gtk_theme != NULL) { + gtk_settings_set_string_property(settings, "gtk-theme-name", + original_gtk_theme, "audacious"); + g_free(original_gtk_theme); + original_gtk_theme = NULL; + } + +#ifndef _WIN32 + if (!config.disable_inline_gtk && !archive) { + gtkrcpath = find_path_recursively(skin->path, "gtkrc"); + if (gtkrcpath != NULL) + skin_set_gtk_theme(settings, skin); + g_free(gtkrcpath); + } +#endif + + if(archive) del_directory(skin_path); + g_free(skin_path); + + gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + config.player_shaded), 0, 0); + gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + config.equalizer_shaded), 0, 0); + + return TRUE; +} + +void +skin_install_skin(const gchar * path) +{ +#if 0 + gchar *command; + + g_return_if_fail(path != NULL); + + command = g_strdup_printf("cp %s %s", + path, aud_paths[BMP_PATH_USER_SKIN_DIR]); + if (system(command)) { + AUDDBG("Unable to install skin (%s) into user directory (%s)\n", + path, aud_paths[BMP_PATH_USER_SKIN_DIR]); + } + g_free(command); +#endif +} + +static SkinPixmap * +skin_get_pixmap(Skin * skin, SkinPixmapId map_id) +{ + g_return_val_if_fail(skin != NULL, NULL); + g_return_val_if_fail(map_id < SKIN_PIXMAP_COUNT, NULL); + + return &skin->pixmaps[map_id]; +} + +gboolean +skin_load(Skin * skin, const gchar * path) +{ + gboolean ret; + + g_return_val_if_fail(skin != NULL, FALSE); + + if (!path) + return FALSE; + + skin_lock(skin); + ret = skin_load_nolock(skin, path, FALSE); + skin_unlock(skin); + + if(!ret) { + AUDDBG("loading failed\n"); + return FALSE; /* don't try to update anything if loading failed --asphyx */ + } + + SkinPixmap *pixmap = NULL; + pixmap = skin_get_pixmap(skin, SKIN_NUMBERS); + if (pixmap) { + ui_skinned_number_set_size(mainwin_minus_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_10min_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_min_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_10sec_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_sec_num, 9, pixmap->height); + } + + pixmap = skin_get_pixmap(skin, SKIN_MAIN); + if (pixmap && skin->properties.mainwin_height > pixmap->height) + skin->properties.mainwin_height = pixmap->height; + + pixmap = skin_get_pixmap(skin, SKIN_PLAYPAUSE); + if (pixmap) + ui_skinned_playstatus_set_size(mainwin_playstatus, 11, pixmap->height); + + pixmap = skin_get_pixmap(skin, SKIN_EQMAIN); + if (pixmap->height >= 313) + gtk_widget_show(equalizerwin_graph); + + return TRUE; +} + +gboolean +skin_reload_forced(void) +{ + gboolean error; + AUDDBG("\n"); + + skin_lock(aud_active_skin); + error = skin_load_nolock(aud_active_skin, aud_active_skin->path, TRUE); + skin_unlock(aud_active_skin); + + return error; +} + +void +skin_reload(Skin * skin) +{ + AUDDBG("\n"); + g_return_if_fail(skin != NULL); + skin_load_nolock(skin, skin->path, TRUE); +} + +GdkBitmap * +skin_get_mask(Skin * skin, SkinMaskId mi) +{ + GdkBitmap **masks; + + g_return_val_if_fail(skin != NULL, NULL); + g_return_val_if_fail(mi < SKIN_PIXMAP_COUNT, NULL); + + masks = config.scaled ? skin->scaled_masks : skin->masks; + return masks[mi]; +} + +GdkColor * +skin_get_color(Skin * skin, SkinColorId color_id) +{ + GdkColor *ret = NULL; + + g_return_val_if_fail(skin != NULL, NULL); + + switch (color_id) { + case SKIN_TEXTBG: + if (skin->pixmaps[SKIN_TEXT].pixbuf) + ret = skin->textbg; + else + ret = skin->def_textbg; + break; + case SKIN_TEXTFG: + if (skin->pixmaps[SKIN_TEXT].pixbuf) + ret = skin->textfg; + else + ret = skin->def_textfg; + break; + default: + if (color_id < SKIN_COLOR_COUNT) + ret = skin->colors[color_id]; + break; + } + return ret; +} + +void +skin_get_viscolor(Skin * skin, guchar vis_color[24][3]) +{ + gint i; + + g_return_if_fail(skin != NULL); + + for (i = 0; i < 24; i++) { + vis_color[i][0] = skin->vis_color[i][0]; + vis_color[i][1] = skin->vis_color[i][1]; + vis_color[i][2] = skin->vis_color[i][2]; + } +} + +gint +skin_get_id(void) +{ + return skin_current_num; +} + +void +skin_draw_pixbuf(GtkWidget *widget, Skin * skin, GdkPixbuf * pix, + SkinPixmapId pixmap_id, + gint xsrc, gint ysrc, gint xdest, gint ydest, + gint width, gint height) +{ + SkinPixmap *pixmap; + + g_return_if_fail(skin != NULL); + + pixmap = skin_get_pixmap(skin, pixmap_id); + g_return_if_fail(pixmap != NULL); + g_return_if_fail(pixmap->pixbuf != NULL); + + /* perhaps we should use transparency or resize widget? */ + if (xsrc+width > pixmap->width || ysrc+height > pixmap->height) { + if (widget) { + /* it's better to hide widget using SKIN_PLAYPAUSE/SKIN_POSBAR than display mess */ + if ((pixmap_id == SKIN_PLAYPAUSE && pixmap->width != 42) || pixmap_id == SKIN_POSBAR) { + gtk_widget_hide(widget); + return; + } + gint x, y; + x = -1; + y = -1; + + if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(mainwin)->fixed) { + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + if (child_data->widget == widget) { + x = child_data->x; + y = child_data->y; + break; + } + } + + if (x != -1 && y != -1) { + /* Some skins include SKIN_VOLUME and/or SKIN_BALANCE + without knobs */ + if (pixmap_id == SKIN_VOLUME || pixmap_id == SKIN_BALANCE) { + if (ysrc+height > 421 && xsrc+width <= pixmap->width) + return; + } + /* let's copy what's under widget */ + gdk_pixbuf_copy_area(skin_get_pixmap(aud_active_skin, SKIN_MAIN)->pixbuf, + x, y, width, height, pix, xdest, ydest); + + /* XMMS skins seems to have SKIN_MONOSTEREO with size 58x20 instead of 58x24 */ + if (pixmap_id == SKIN_MONOSTEREO) + height = pixmap->height/2; + } + } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(equalizerwin)->fixed) { + if (!(pixmap_id == SKIN_EQMAIN && ysrc == 314)) /* equalizer preamp on equalizer graph */ + gtk_widget_hide(widget); + } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(playlistwin)->fixed) { + /* I haven't seen any skin with substandard playlist */ + gtk_widget_hide(widget); + } + } else + return; + } + + width = MIN(width, pixmap->width - xsrc); + height = MIN(height, pixmap->height - ysrc); + gdk_pixbuf_copy_area(pixmap->pixbuf, xsrc, ysrc, width, height, + pix, xdest, ydest); +} + +void +skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]) +{ + gint i; + GdkPixbuf *pixbuf; + SkinPixmap *eqmainpm; + guchar* pixels,*p; + guint rowstride, n_channels; + g_return_if_fail(skin != NULL); + + eqmainpm = &skin->pixmaps[SKIN_EQMAIN]; + if (eqmainpm->pixbuf && + eqmainpm->current_width >= 116 && eqmainpm->current_height >= 313) + pixbuf = eqmainpm->pixbuf; + else + return; + + if (!GDK_IS_PIXBUF(pixbuf)) + return; + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + for (i = 0; i < 19; i++) + { + p = pixels + rowstride * (i + 294) + 115 * n_channels; + colors[i] = (p[0] << 16) | (p[1] << 8) | p[2]; + /* should we really treat the Alpha channel? */ + /*if (n_channels == 4) + colors[i] = (colors[i] << 8) | p[3];*/ + } +} + + +static void +skin_draw_playlistwin_frame_top(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + /* The title bar skin consists of 2 sets of 4 images, 1 set + * for focused state and the other for unfocused. The 4 images + * are: + * + * a. right corner (25,20) + * b. left corner (25,20) + * c. tiler (25,20) + * d. title (100,20) + * + * min allowed width = 100+25+25 = 150 + */ + + gint i, y, c; + + /* get y offset of the pixmap set to use */ + if (focus) + y = 0; + else + y = 21; + + /* left corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, y, 0, 0, 25, 20); + + /* titlebar title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 26, y, + (width - 100) / 2, 0, 100, 20); + + /* titlebar right corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 153, y, + width - 25, 0, 25, 20); + + /* tile draw the remaining frame */ + + /* compute tile count */ + c = (width - (100 + 25 + 25)) / 25; + + for (i = 0; i < c / 2; i++) { + /* left of title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + 25 + i * 25, 0, 25, 20); + + /* right of title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + (width + 100) / 2 + i * 25, 0, 25, 20); + } + + if (c & 1) { + /* Odd tile count, so one remaining to draw. Here we split + * it into two and draw half on either side of the title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + ((c / 2) * 25) + 25, 0, 12, 20); + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + (width / 2) + ((c / 2) * 25) + 50, 0, 13, 20); + } +} + +static void +skin_draw_playlistwin_frame_bottom(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + /* The bottom frame skin consists of 1 set of 4 images. The 4 + * images are: + * + * a. left corner with menu buttons (125,38) + * b. visualization window (75,38) + * c. right corner with play buttons (150,38) + * d. frame tile (25,38) + * + * (min allowed width = 125+150+25=300 + */ + + gint i, c; + + /* bottom left corner (menu buttons) */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, 72, + 0, height - 38, 125, 38); + + c = (width - 275) / 25; + + /* draw visualization window, if width allows */ + if (c >= 3) { + c -= 3; + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 205, 0, + width - (150 + 75), height - 38, 75, 38); + } + + /* Bottom right corner (playbuttons etc) */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, + 126, 72, width - 150, height - 38, 150, 38); + + /* Tile draw the remaining undrawn portions */ + for (i = 0; i < c; i++) + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 179, 0, + 125 + i * 25, height - 38, 25, 38); +} + +static void +skin_draw_playlistwin_frame_sides(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + /* The side frames consist of 2 tile images. 1 for the left, 1 for + * the right. + * a. left (12,29) + * b. right (19,29) + */ + + gint i; + + /* frame sides */ + for (i = 0; i < (height - (20 + 38)) / 29; i++) { + /* left */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, 42, + 0, 20 + i * 29, 12, 29); + + /* right */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 32, 42, + width - 19, 20 + i * 29, 19, 29); + } +} + + +void +skin_draw_playlistwin_frame(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + skin_draw_playlistwin_frame_top(skin, pix, width, height, focus); + skin_draw_playlistwin_frame_bottom(skin, pix, width, height, focus); + skin_draw_playlistwin_frame_sides(skin, pix, width, height, focus); +} + + +void +skin_draw_playlistwin_shaded(Skin * skin, GdkPixbuf * pix, + gint width, gboolean focus) +{ + /* The shade mode titlebar skin consists of 4 images: + * a) left corner offset (72,42) size (25,14) + * b) right corner, focused offset (99,57) size (50,14) + * c) right corner, unfocused offset (99,42) size (50,14) + * d) bar tile offset (72,57) size (25,14) + */ + + gint i; + + /* left corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 72, 42, 0, 0, 25, 14); + + /* bar tile */ + for (i = 0; i < (width - 75) / 25; i++) + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 72, 57, + (i * 25) + 25, 0, 25, 14); + + /* right corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 99, focus ? 42 : 57, + width - 50, 0, 50, 14); +} + + +void +skin_draw_mainwin_titlebar(Skin * skin, GdkPixbuf * pix, + gboolean shaded, gboolean focus) +{ + /* The titlebar skin consists of 2 sets of 2 images, one for for + * shaded and the other for unshaded mode, giving a total of 4. + * The images are exactly 275x14 pixels, aligned and arranged + * vertically on each other in the pixmap in the following order: + * + * a) unshaded, focused offset (27, 0) + * b) unshaded, unfocused offset (27, 15) + * c) shaded, focused offset (27, 29) + * d) shaded, unfocused offset (27, 42) + */ + + gint y_offset; + + if (shaded) { + if (focus) + y_offset = 29; + else + y_offset = 42; + } + else { + if (focus) + y_offset = 0; + else + y_offset = 15; + } + + skin_draw_pixbuf(NULL, skin, pix, SKIN_TITLEBAR, 27, y_offset, + 0, 0, aud_active_skin->properties.mainwin_width, MAINWIN_TITLEBAR_HEIGHT); +} + + +void +skin_set_random_skin(void) +{ +#if 0 + SkinNode *node; + guint32 randval; + + /* Get a random value to select the skin to use */ + randval = g_random_int_range(0, g_list_length(skinlist)); + node = g_list_nth(skinlist, randval)->data; + aud_active_skin_load(node->path); +#endif +} + + +void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale) { + g_return_if_fail(widget != NULL); + g_return_if_fail(obj != NULL); + + if (scale) { + GdkPixbuf *image = gdk_pixbuf_scale_simple(obj, width * config.scale_factor, height* aud_cfg->scale_factor, GDK_INTERP_NEAREST); + gdk_draw_pixbuf(widget->window, NULL, image, 0, 0, 0, 0, width * config.scale_factor , height * aud_cfg->scale_factor, GDK_RGB_DITHER_NONE, 0, 0); + g_object_unref(image); + } else { + gdk_draw_pixbuf(widget->window, NULL, obj, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skin.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,244 @@ +/* Audacious + * Copyright (C) 2005-2007 Audacious development team. + * + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef SKIN_H +#define SKIN_H + +#include <glib.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +#define BMP_DEFAULT_SKIN_PATH \ + DATA_DIR G_DIR_SEPARATOR_S "Skins" G_DIR_SEPARATOR_S "Default" + +typedef enum { + SKIN_MAIN = 0, + SKIN_CBUTTONS, + SKIN_TITLEBAR, + SKIN_SHUFREP, + SKIN_TEXT, + SKIN_VOLUME, + SKIN_BALANCE, + SKIN_MONOSTEREO, + SKIN_PLAYPAUSE, + SKIN_NUMBERS, + SKIN_POSBAR, + SKIN_PLEDIT, + SKIN_EQMAIN, + SKIN_EQ_EX, + SKIN_PIXMAP_COUNT +} SkinPixmapId; + +typedef enum { + SKIN_MASK_MAIN = 0, + SKIN_MASK_MAIN_SHADE, + SKIN_MASK_EQ, + SKIN_MASK_EQ_SHADE, + SKIN_MASK_COUNT +} SkinMaskId; + +typedef enum { + SKIN_PLEDIT_NORMAL = 0, + SKIN_PLEDIT_CURRENT, + SKIN_PLEDIT_NORMALBG, + SKIN_PLEDIT_SELECTEDBG, + SKIN_TEXTBG, + SKIN_TEXTFG, + SKIN_COLOR_COUNT +} SkinColorId; + +typedef struct _SkinProperties { + /* this enables the othertext engine, not it's visibility -nenolod */ + gboolean mainwin_othertext; + + /* Vis properties */ + gint mainwin_vis_x; + gint mainwin_vis_y; + gint mainwin_vis_width; + gboolean mainwin_vis_visible; + + /* Text properties */ + gint mainwin_text_x; + gint mainwin_text_y; + gint mainwin_text_width; + gboolean mainwin_text_visible; + + /* Infobar properties */ + gint mainwin_infobar_x; + gint mainwin_infobar_y; + gboolean mainwin_othertext_visible; + + gint mainwin_number_0_x; + gint mainwin_number_0_y; + + gint mainwin_number_1_x; + gint mainwin_number_1_y; + + gint mainwin_number_2_x; + gint mainwin_number_2_y; + + gint mainwin_number_3_x; + gint mainwin_number_3_y; + + gint mainwin_number_4_x; + gint mainwin_number_4_y; + + gint mainwin_playstatus_x; + gint mainwin_playstatus_y; + + gint mainwin_volume_x; + gint mainwin_volume_y; + + gint mainwin_balance_x; + gint mainwin_balance_y; + + gint mainwin_position_x; + gint mainwin_position_y; + + gint mainwin_previous_x; + gint mainwin_previous_y; + + gint mainwin_play_x; + gint mainwin_play_y; + + gint mainwin_pause_x; + gint mainwin_pause_y; + + gint mainwin_stop_x; + gint mainwin_stop_y; + + gint mainwin_next_x; + gint mainwin_next_y; + + gint mainwin_eject_x; + gint mainwin_eject_y; + + gint mainwin_eqbutton_x; + gint mainwin_eqbutton_y; + + gint mainwin_plbutton_x; + gint mainwin_plbutton_y; + + gint mainwin_shuffle_x; + gint mainwin_shuffle_y; + + gint mainwin_repeat_x; + gint mainwin_repeat_y; + + gint mainwin_about_x; + gint mainwin_about_y; + + gint mainwin_minimize_x; + gint mainwin_minimize_y; + + gint mainwin_shade_x; + gint mainwin_shade_y; + + gint mainwin_close_x; + gint mainwin_close_y; + + gint mainwin_width; + gint mainwin_height; + + gboolean mainwin_menurow_visible; + gboolean mainwin_othertext_is_status; + + gint textbox_bitmap_font_width; + gint textbox_bitmap_font_height; +} SkinProperties; + +#define SKIN_PIXMAP(x) ((SkinPixmap *)(x)) +typedef struct _SkinPixmap { + GdkPixbuf *pixbuf; + + /* The real size of the pixmap */ + gint width, height; + + /* The size of the pixmap from the current skin, + which might be smaller */ + gint current_width, current_height; +} SkinPixmap; + + +#define SKIN(x) ((Skin *)(x)) +typedef struct _Skin { + GMutex *lock; + gchar *path; + gchar *def_path; + SkinPixmap pixmaps[SKIN_PIXMAP_COUNT]; + GdkColor textbg[6], def_textbg[6]; + GdkColor textfg[6], def_textfg[6]; + GdkColor *colors[SKIN_COLOR_COUNT]; + guchar vis_color[24][3]; + GdkBitmap *masks[SKIN_MASK_COUNT]; + GdkBitmap *scaled_masks[SKIN_MASK_COUNT]; + SkinProperties properties; +} Skin; + +extern Skin *aud_active_skin; + +gboolean init_skins(const gchar * path); +void cleanup_skins(void); + +gboolean aud_active_skin_load(const gchar * path); +gboolean aud_active_skin_reload(void); + +Skin *skin_new(void); +gboolean skin_load(Skin * skin, const gchar * path); +gboolean skin_reload_forced(void); +void skin_reload(Skin * skin); +void skin_free(Skin * skin); + +GdkBitmap *skin_get_mask(Skin * skin, SkinMaskId mi); +GdkColor *skin_get_color(Skin * skin, SkinColorId color_id); + +void skin_get_viscolor(Skin * skin, guchar vis_color[24][3]); +gint skin_get_id(void); +void skin_draw_pixbuf(GtkWidget *widget, Skin * skin, GdkPixbuf * pix, + SkinPixmapId pixmap_id, + gint xsrc, gint ysrc, gint xdest, gint ydest, + gint width, gint height); + +void skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]); +void skin_install_skin(const gchar * path); + +void skin_draw_playlistwin_shaded(Skin * skin, GdkPixbuf * pix, + gint width, gboolean focus); +void skin_draw_playlistwin_frame(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus); + +void skin_draw_mainwin_titlebar(Skin * skin, GdkPixbuf * pix, + gboolean shaded, gboolean focus); + + +void skin_parse_hints(Skin * skin, gchar *path_p); + + +void skin_set_random_skin(void); + + +void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_button.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,536 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skinned_button.h" +#include "skins_cfg.h" +#include <math.h> + +#define UI_SKINNED_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_button_get_type(), UiSkinnedButtonPrivate)) +typedef struct _UiSkinnedButtonPrivate UiSkinnedButtonPrivate; + +enum { + PRESSED, + RELEASED, + CLICKED, + DOUBLED, + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedButtonPrivate { + //Skinned part + GdkGC *gc; + gint w; + gint h; + SkinPixmapId skin_index1; + SkinPixmapId skin_index2; + gboolean scaled; + gint move_x, move_y; + + gint nx, ny, px, py; + //Toogle button needs also those + gint pnx, pny, ppx, ppy; +}; + + +static GtkWidgetClass *parent_class = NULL; +static void ui_skinned_button_class_init(UiSkinnedButtonClass *klass); +static void ui_skinned_button_init(UiSkinnedButton *button); +static void ui_skinned_button_destroy(GtkObject *object); +static void ui_skinned_button_realize(GtkWidget *widget); +static void ui_skinned_button_unrealize(GtkWidget *widget); +static void ui_skinned_button_map(GtkWidget *widget); +static void ui_skinned_button_unmap(GtkWidget *widget); +static void ui_skinned_button_size_request(GtkWidget *widget, GtkRequisition *requisition); +static gint ui_skinned_button_expose(GtkWidget *widget,GdkEventExpose *event); + +static void ui_skinned_button_size_allocate(GtkWidget *widget, GtkAllocation *allocation); +static void ui_skinned_button_update_state(UiSkinnedButton *button); + +static guint button_signals[LAST_SIGNAL] = { 0 }; +static gint ui_skinned_button_button_press(GtkWidget *widget, GdkEventButton *event); +static gint ui_skinned_button_button_release(GtkWidget *widget, GdkEventButton *event); +static void button_pressed(UiSkinnedButton *button); +static void button_released(UiSkinnedButton *button); +static void ui_skinned_button_pressed(UiSkinnedButton *button); +static void ui_skinned_button_released(UiSkinnedButton *button); +static void ui_skinned_button_clicked(UiSkinnedButton *button); +static void ui_skinned_button_set_pressed (UiSkinnedButton *button, gboolean pressed); + +static void ui_skinned_button_toggle_scaled(UiSkinnedButton *button); + +static gint ui_skinned_button_enter_notify(GtkWidget *widget, GdkEventCrossing *event); +static gint ui_skinned_button_leave_notify(GtkWidget *widget, GdkEventCrossing *event); +static void ui_skinned_button_redraw(UiSkinnedButton *button); + +GType ui_skinned_button_get_type() { + static GType button_type = 0; + if (!button_type) { + static const GTypeInfo button_info = { + sizeof (UiSkinnedButtonClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_button_class_init, + NULL, + NULL, + sizeof (UiSkinnedButton), + 0, + (GInstanceInitFunc) ui_skinned_button_init, + }; + button_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedButton", &button_info, 0); + } + + return button_type; +} + +static void ui_skinned_button_class_init (UiSkinnedButtonClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_button_destroy; + + widget_class->realize = ui_skinned_button_realize; + widget_class->unrealize = ui_skinned_button_unrealize; + widget_class->map = ui_skinned_button_map; + widget_class->unmap = ui_skinned_button_unmap; + widget_class->expose_event = ui_skinned_button_expose; + widget_class->size_request = ui_skinned_button_size_request; + widget_class->size_allocate = ui_skinned_button_size_allocate; + widget_class->button_press_event = ui_skinned_button_button_press; + widget_class->button_release_event = ui_skinned_button_button_release; + widget_class->enter_notify_event = ui_skinned_button_enter_notify; + widget_class->leave_notify_event = ui_skinned_button_leave_notify; + + klass->pressed = button_pressed; + klass->released = button_released; + klass->clicked = NULL; + klass->scaled = ui_skinned_button_toggle_scaled; + klass->redraw = ui_skinned_button_redraw; + + button_signals[PRESSED] = + g_signal_new ("pressed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (UiSkinnedButtonClass, pressed), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[RELEASED] = + g_signal_new ("released", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (UiSkinnedButtonClass, released), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[CLICKED] = + g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedButtonClass, clicked), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedButtonClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedButtonClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedButtonPrivate)); +} + +static void ui_skinned_button_init (UiSkinnedButton *button) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + button->inside = FALSE; + button->type = TYPE_NOT_SET; + priv->move_x = 0; + priv->move_y = 0; + button->event_window = NULL; +} + +static void ui_skinned_button_destroy (GtkObject *object) { + UiSkinnedButton *button; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_BUTTON (object)); + + button = UI_SKINNED_BUTTON(object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_button_realize (GtkWidget *widget) { + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_BUTTON(widget)); + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + GdkWindowAttr attributes; + gint attributes_mask; + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; + + if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + attributes.wclass = GDK_INPUT_ONLY; + attributes_mask = GDK_WA_X | GDK_WA_Y; + button->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); + GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(button->event_window, widget); + } else { + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(widget->window, widget); + } + + widget->style = gtk_style_attach(widget->style, widget->window); +} + +static void ui_skinned_button_unrealize (GtkWidget *widget) { + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + + if ( button->event_window != NULL ) + { + gdk_window_set_user_data( button->event_window , NULL ); + gdk_window_destroy( button->event_window ); + button->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void ui_skinned_button_map (GtkWidget *widget) +{ + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + + if (button->event_window != NULL) + gdk_window_show (button->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->map) + (* GTK_WIDGET_CLASS (parent_class)->map) (widget); +} + +static void ui_skinned_button_unmap (GtkWidget *widget) +{ + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + + if (button->event_window != NULL) + gdk_window_hide (button->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->unmap) + (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); +} + +static void ui_skinned_button_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(widget); + requisition->width = priv->w*(priv->scaled ? config.scale_factor : 1); + requisition->height = priv->h*(priv->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_button_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + widget->allocation = *allocation; + widget->allocation.x = ceil(widget->allocation.x*(priv->scaled ? config.scale_factor : 1)); + widget->allocation.y = ceil(widget->allocation.y*(priv->scaled ? config.scale_factor : 1)); + + if (GTK_WIDGET_REALIZED (widget)) + { + if ( button->event_window != NULL ) + gdk_window_move_resize(button->event_window, ceil(allocation->x*(priv->scaled ? config.scale_factor : 1)), ceil(allocation->y*(priv->scaled ? config.scale_factor : 1)), allocation->width, allocation->height); + else + gdk_window_move_resize(widget->window, ceil(allocation->x*(priv->scaled ? config.scale_factor : 1)), ceil(allocation->y*(priv->scaled ? config.scale_factor : 1)), allocation->width, allocation->height); + } + + if (button->x + priv->move_x == ceil(widget->allocation.x/(priv->scaled ? config.scale_factor : 1))) + priv->move_x = 0; + if (button->y + priv->move_y == ceil(widget->allocation.y/(priv->scaled ? config.scale_factor : 1))) + priv->move_y = 0; + + button->x = ceil(widget->allocation.x/(priv->scaled ? config.scale_factor : 1)); + button->y = ceil(widget->allocation.y/(priv->scaled ? config.scale_factor : 1)); +} + +static gboolean ui_skinned_button_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + g_return_val_if_fail (priv->w > 0 && priv->h > 0, FALSE); + + //TYPE_SMALL doesn't have its own face + if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) + return FALSE; + + /* paranoia */ + if (button->event_window != NULL) + return FALSE; + + GdkPixbuf *obj; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->w, priv->h); + + switch (button->type) { + case TYPE_PUSH: + skin_draw_pixbuf(widget, aud_active_skin, obj, + button->pressed ? priv->skin_index2 : priv->skin_index1, + button->pressed ? priv->px : priv->nx, + button->pressed ? priv->py : priv->ny, + 0, 0, priv->w, priv->h); + break; + case TYPE_TOGGLE: + if (button->inside) + skin_draw_pixbuf(widget, aud_active_skin, obj, + button->pressed ? priv->skin_index2 : priv->skin_index1, + button->pressed ? priv->ppx : priv->pnx, + button->pressed ? priv->ppy : priv->pny, + 0, 0, priv->w, priv->h); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, + button->pressed ? priv->skin_index2 : priv->skin_index1, + button->pressed ? priv->px : priv->nx, + button->pressed ? priv->py : priv->ny, + 0, 0, priv->w, priv->h); + break; + default: + break; + } + + ui_skinned_widget_draw(widget, obj, priv->w, priv->h, priv->scaled); + g_object_unref(obj); + + return FALSE; +} + +GtkWidget* ui_skinned_button_new () { + UiSkinnedButton *button = g_object_new (ui_skinned_button_get_type (), NULL); + + return GTK_WIDGET(button); +} + +void ui_skinned_push_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si) { + + UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); + priv->w = w; + priv->h = h; + sbutton->x = x; + sbutton->y = y; + priv->nx = nx; + priv->ny = ny; + priv->px = px; + priv->py = py; + sbutton->type = TYPE_PUSH; + priv->skin_index1 = si; + priv->skin_index2 = si; + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); +} + +void ui_skinned_toggle_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, gint pnx, gint pny, gint ppx, gint ppy, SkinPixmapId si) { + + UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); + priv->w = w; + priv->h = h; + sbutton->x = x; + sbutton->y = y; + priv->nx = nx; + priv->ny = ny; + priv->px = px; + priv->py = py; + priv->pnx = pnx; + priv->pny = pny; + priv->ppx = ppx; + priv->ppy = ppy; + sbutton->type = TYPE_TOGGLE; + priv->skin_index1 = si; + priv->skin_index2 = si; + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); +} + +void ui_skinned_small_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h) { + + UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); + priv->w = w; + priv->h = h; + sbutton->x = x; + sbutton->y = y; + sbutton->type = TYPE_SMALL; + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); +} + +static void button_pressed(UiSkinnedButton *button) { + button->button_down = TRUE; + ui_skinned_button_update_state(button); +} + +static void button_released(UiSkinnedButton *button) { + button->button_down = FALSE; + if(button->hover) ui_skinned_button_clicked(button); + ui_skinned_button_update_state(button); +} + +static void ui_skinned_button_update_state(UiSkinnedButton *button) { + ui_skinned_button_set_pressed(button, button->button_down); +} + +static void ui_skinned_button_set_pressed (UiSkinnedButton *button, gboolean pressed) { + if (pressed != button->pressed) { + button->pressed = pressed; + gtk_widget_queue_draw(GTK_WIDGET(button)); + } +} + +static gboolean ui_skinned_button_button_press(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedButton *button; + + if (event->type == GDK_BUTTON_PRESS) { + button = UI_SKINNED_BUTTON(widget); + + if (event->button == 1) + ui_skinned_button_pressed (button); + else if (event->button == 3) { + event->x = event->x + button->x; + event->y = event->y + button->y; + return FALSE; + } + } + + return TRUE; +} + +static gboolean ui_skinned_button_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedButton *button; + if (event->button == 1) { + button = UI_SKINNED_BUTTON(widget); + ui_skinned_button_released(button); + } + return TRUE; +} + +static void ui_skinned_button_pressed(UiSkinnedButton *button) { + g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); + g_signal_emit(button, button_signals[PRESSED], 0); +} + +static void ui_skinned_button_released(UiSkinnedButton *button) { + g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); + g_signal_emit(button, button_signals[RELEASED], 0); +} + +static void ui_skinned_button_clicked(UiSkinnedButton *button) { + g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); + button->inside = !button->inside; + g_signal_emit(button, button_signals[CLICKED], 0); +} + +static gboolean ui_skinned_button_enter_notify(GtkWidget *widget, GdkEventCrossing *event) { + UiSkinnedButton *button; + + button = UI_SKINNED_BUTTON(widget); + button->hover = TRUE; + if(button->button_down) ui_skinned_button_set_pressed(button, TRUE); + + return FALSE; +} + +static gboolean ui_skinned_button_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { + UiSkinnedButton *button; + + button = UI_SKINNED_BUTTON (widget); + button->hover = FALSE; + if(button->button_down) ui_skinned_button_set_pressed(button, FALSE); + + return FALSE; +} + +static void ui_skinned_button_toggle_scaled(UiSkinnedButton *button) { + GtkWidget *widget = GTK_WIDGET (button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, priv->w*(priv->scaled ? config.scale_factor : 1), priv->h*(priv->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(widget); +} + +static void ui_skinned_button_redraw(UiSkinnedButton *button) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + if (priv->move_x || priv->move_y) + gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(button))), GTK_WIDGET(button), + button->x+priv->move_x, button->y+priv->move_y); + + gtk_widget_queue_draw(GTK_WIDGET(button)); +} + + +void ui_skinned_set_push_button_data(GtkWidget *button, gint nx, gint ny, gint px, gint py) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(button); + if (nx > -1) priv->nx = nx; + if (ny > -1) priv->ny = ny; + if (px > -1) priv->px = px; + if (py > -1) priv->py = py; + gtk_widget_queue_draw(button); +} + +void ui_skinned_button_set_skin_index(GtkWidget *button, SkinPixmapId si) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->skin_index1 = priv->skin_index2 = si; +} + +void ui_skinned_button_set_skin_index1(GtkWidget *button, SkinPixmapId si) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->skin_index1 = si; +} + +void ui_skinned_button_set_skin_index2(GtkWidget *button, SkinPixmapId si) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->skin_index2 = si; +} + +void ui_skinned_button_move_relative(GtkWidget *button, gint x, gint y) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->move_x += x; + priv->move_y += y; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_button.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_BUTTON_H +#define AUDACIOUS_UI_SKINNED_BUTTON_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#define UI_SKINNED_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ui_skinned_button_get_type(), UiSkinnedButton)) +#define UI_SKINNED_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ui_skinned_button_get_type(), UiSkinnedButtonClass)) +#define UI_SKINNED_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ui_skinned_button_get_type())) + +typedef struct _UiSkinnedButton UiSkinnedButton; +typedef struct _UiSkinnedButtonClass UiSkinnedButtonClass; + +enum { + TYPE_NOT_SET, + TYPE_PUSH, + TYPE_TOGGLE, + TYPE_SMALL +}; + +struct _UiSkinnedButton { + GtkWidget widget; + + GdkWindow *event_window; + gboolean button_down; + gboolean pressed; + gboolean hover; + gboolean inside; + gint type; + gint x, y; +}; + +struct _UiSkinnedButtonClass { + GtkWidgetClass parent_class; + void (* pressed) (UiSkinnedButton *button); + void (* released) (UiSkinnedButton *button); + void (* clicked) (UiSkinnedButton *button); + void (* right_clicked) (UiSkinnedButton *button); + void (* scaled) (UiSkinnedButton *button); + void (* redraw) (UiSkinnedButton *button); +}; + +GType ui_skinned_button_get_type(void) G_GNUC_CONST; +GtkWidget* ui_skinned_button_new(); +void ui_skinned_push_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si); +void ui_skinned_set_push_button_data(GtkWidget *button, gint nx, gint ny, gint px, gint py); +void ui_skinned_toggle_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, gint pnx, gint pny, gint ppx, gint ppy, SkinPixmapId si); +void ui_skinned_small_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h); +void ui_skinned_button_set_skin_index(GtkWidget *button, SkinPixmapId si); +void ui_skinned_button_set_skin_index1(GtkWidget *button, SkinPixmapId si); +void ui_skinned_button_set_skin_index2(GtkWidget *button, SkinPixmapId si); +void ui_skinned_button_move_relative(GtkWidget *button, gint x, gint y); + +#endif /* AUDACIOUS_UI_SKINNED_BUTTON_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_equalizer_graph.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,307 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses>. + */ + +#include "ui_skin.h" +#include "ui_skinned_equalizer_graph.h" +#include "skins_cfg.h" +#include <audacious/plugin.h> + +#define UI_TYPE_SKINNED_EQUALIZER_GRAPH (ui_skinned_equalizer_graph_get_type()) + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_equalizer_graph_class_init (UiSkinnedEqualizerGraphClass *klass); +static void ui_skinned_equalizer_graph_init (UiSkinnedEqualizerGraph *equalizer_graph); +static void ui_skinned_equalizer_graph_destroy (GtkObject *object); +static void ui_skinned_equalizer_graph_realize (GtkWidget *widget); +static void ui_skinned_equalizer_graph_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_equalizer_graph_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_equalizer_graph_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_equalizer_graph_toggle_scaled (UiSkinnedEqualizerGraph *equalizer_graph); + +static GtkWidgetClass *parent_class = NULL; +static guint equalizer_graph_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_equalizer_graph_get_type() { + static GType equalizer_graph_type = 0; + if (!equalizer_graph_type) { + static const GTypeInfo equalizer_graph_info = { + sizeof (UiSkinnedEqualizerGraphClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_equalizer_graph_class_init, + NULL, + NULL, + sizeof (UiSkinnedEqualizerGraph), + 0, + (GInstanceInitFunc) ui_skinned_equalizer_graph_init, + }; + equalizer_graph_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedEqualizerGraph", &equalizer_graph_info, 0); + } + + return equalizer_graph_type; +} + +static void ui_skinned_equalizer_graph_class_init(UiSkinnedEqualizerGraphClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_equalizer_graph_destroy; + + widget_class->realize = ui_skinned_equalizer_graph_realize; + widget_class->expose_event = ui_skinned_equalizer_graph_expose; + widget_class->size_request = ui_skinned_equalizer_graph_size_request; + widget_class->size_allocate = ui_skinned_equalizer_graph_size_allocate; + + klass->scaled = ui_skinned_equalizer_graph_toggle_scaled; + + equalizer_graph_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedEqualizerGraphClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_equalizer_graph_init(UiSkinnedEqualizerGraph *equalizer_graph) { + equalizer_graph->width = 113; + equalizer_graph->height = 19; +} + +GtkWidget* ui_skinned_equalizer_graph_new(GtkWidget *fixed, gint x, gint y) { + UiSkinnedEqualizerGraph *equalizer_graph = g_object_new (ui_skinned_equalizer_graph_get_type (), NULL); + + equalizer_graph->x = x; + equalizer_graph->y = y; + equalizer_graph->skin_index = SKIN_EQMAIN; + equalizer_graph->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(equalizer_graph), equalizer_graph->x, equalizer_graph->y); + + return GTK_WIDGET(equalizer_graph); +} + +static void ui_skinned_equalizer_graph_destroy(GtkObject *object) { + UiSkinnedEqualizerGraph *equalizer_graph; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH (object)); + + equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_equalizer_graph_realize(GtkWidget *widget) { + UiSkinnedEqualizerGraph *equalizer_graph; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_equalizer_graph_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH(widget); + + requisition->width = equalizer_graph->width*(equalizer_graph->scaled ? config.scale_factor : 1); + requisition->height = equalizer_graph->height*(equalizer_graph->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_equalizer_graph_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (equalizer_graph->scaled ? config.scale_factor : 1); + widget->allocation.y *= (equalizer_graph->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + equalizer_graph->x = widget->allocation.x/(equalizer_graph->scaled ? config.scale_factor : 1); + equalizer_graph->y = widget->allocation.y/(equalizer_graph->scaled ? config.scale_factor : 1); +} + +void +init_spline(gfloat * x, gfloat * y, gint n, gfloat * y2) +{ + gint i, k; + gfloat p, qn, sig, un, *u; + + u = (gfloat *) g_malloc(n * sizeof(gfloat)); + + y2[0] = u[0] = 0.0; + + for (i = 1; i < n - 1; i++) { + sig = ((gfloat) x[i] - x[i - 1]) / ((gfloat) x[i + 1] - x[i - 1]); + p = sig * y2[i - 1] + 2.0; + y2[i] = (sig - 1.0) / p; + u[i] = + (((gfloat) y[i + 1] - y[i]) / (x[i + 1] - x[i])) - + (((gfloat) y[i] - y[i - 1]) / (x[i] - x[i - 1])); + u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + qn = un = 0.0; + + y2[n - 1] = (un - qn * u[n - 2]) / (qn * y2[n - 2] + 1.0); + for (k = n - 2; k >= 0; k--) + y2[k] = y2[k] * y2[k + 1] + u[k]; + g_free(u); +} + +gfloat +eval_spline(gfloat xa[], gfloat ya[], gfloat y2a[], gint n, gfloat x) +{ + gint klo, khi, k; + gfloat h, b, a; + + klo = 0; + khi = n - 1; + while (khi - klo > 1) { + k = (khi + klo) >> 1; + if (xa[k] > x) + khi = k; + else + klo = k; + } + h = xa[khi] - xa[klo]; + a = (xa[khi] - x) / h; + b = (x - xa[klo]) / h; + return (a * ya[klo] + b * ya[khi] + + ((a * a * a - a) * y2a[klo] + + (b * b * b - b) * y2a[khi]) * (h * h) / 6.0); +} + +static gboolean ui_skinned_equalizer_graph_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (widget); + g_return_val_if_fail (equalizer_graph->width > 0 && equalizer_graph->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, equalizer_graph->width, equalizer_graph->height); + + guint32 cols[19], rowstride; + gint i, y, ymin, ymax, py = 0; + gfloat x[] = { 0, 11, 23, 35, 47, 59, 71, 83, 97, 109 }, yf[10]; + guchar* pixels, *p; + gint n_channels; + /* + * This avoids the init_spline() function to be inlined. + * Inlining the function caused troubles when compiling with + * `-O' (at least on FreeBSD). + */ + void (*__init_spline) (gfloat *, gfloat *, gint, gfloat *) = init_spline; + + skin_draw_pixbuf(widget, aud_active_skin, obj, equalizer_graph->skin_index, 0, 294, 0, 0, + equalizer_graph->width, equalizer_graph->height); + skin_draw_pixbuf(widget, aud_active_skin, obj, equalizer_graph->skin_index, 0, 314, + 0, 9 + ((aud_cfg->equalizer_preamp * 9) / 20), + equalizer_graph->width, 1); + + skin_get_eq_spline_colors(aud_active_skin, cols); + + __init_spline(x, aud_cfg->equalizer_bands, 10, yf); + for (i = 0; i < 109; i++) { + y = 9 - + (gint) ((eval_spline(x, aud_cfg->equalizer_bands, yf, 10, i) * + 9.0) / EQUALIZER_MAX_GAIN); + if (y < 0) + y = 0; + if (y > 18) + y = 18; + if (!i) + py = y; + if (y < py) { + ymin = y; + ymax = py; + } + else { + ymin = py; + ymax = y; + } + py = y; + + pixels = gdk_pixbuf_get_pixels(obj); + rowstride = gdk_pixbuf_get_rowstride(obj); + n_channels = gdk_pixbuf_get_n_channels(obj); + + for (y = ymin; y <= ymax; y++) + { + p = pixels + (y * rowstride) + (( i + 2) * n_channels); + p[0] = (cols[y] & 0xff0000) >> 16; + p[1] = (cols[y] & 0x00ff00) >> 8; + p[2] = (cols[y] & 0x0000ff); + /* do we really need to treat the alpha channel? */ + /*if (n_channels == 4) + p[3] = cols[y] >> 24;*/ + } + } + + ui_skinned_widget_draw(widget, obj, equalizer_graph->width, equalizer_graph->height, equalizer_graph->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_equalizer_graph_toggle_scaled(UiSkinnedEqualizerGraph *equalizer_graph) { + GtkWidget *widget = GTK_WIDGET (equalizer_graph); + + equalizer_graph->scaled = !equalizer_graph->scaled; + gtk_widget_set_size_request(widget, equalizer_graph->width*(equalizer_graph->scaled ? config.scale_factor : 1), + equalizer_graph->height*(equalizer_graph->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(equalizer_graph)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_equalizer_graph.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H +#define AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define EQUALIZER_MAX_GAIN 12.0 + +#define UI_SKINNED_EQUALIZER_GRAPH(obj) GTK_CHECK_CAST (obj, ui_skinned_equalizer_graph_get_type (), UiSkinnedEqualizerGraph) +#define UI_SKINNED_EQUALIZER_GRAPH_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_equalizer_graph_get_type (), UiSkinnedEqualizerGraphClass) +#define UI_SKINNED_IS_EQUALIZER_GRAPH(obj) GTK_CHECK_TYPE (obj, ui_skinned_equalizer_graph_get_type ()) + +typedef struct _UiSkinnedEqualizerGraph UiSkinnedEqualizerGraph; +typedef struct _UiSkinnedEqualizerGraphClass UiSkinnedEqualizerGraphClass; + +struct _UiSkinnedEqualizerGraph { + GtkWidget widget; + + gint x, y, width, height; + SkinPixmapId skin_index; + gboolean scaled; +}; + +struct _UiSkinnedEqualizerGraphClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedEqualizerGraph *eq_graph); +}; + +GtkWidget* ui_skinned_equalizer_graph_new(GtkWidget *fixed, gint x, gint y); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_equalizer_slider.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,400 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses>. + */ + +#include "ui_skin.h" +#if 0 +#include "ui_equalizer.h" +#endif +#include "ui_main.h" +#include "skins_cfg.h" +#include "ui_skinned_equalizer_slider.h" +#include <glib/gi18n.h> + +#define UI_TYPE_SKINNED_EQUALIZER_SLIDER (ui_skinned_equalizer_slider_get_type()) +#define UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UI_TYPE_SKINNED_EQUALIZER_SLIDER, UiSkinnedEqualizerSliderPrivate)) +typedef struct _UiSkinnedEqualizerSliderPrivate UiSkinnedEqualizerSliderPrivate; + +enum { + DOUBLED, + LAST_SIGNAL +}; + +struct _UiSkinnedEqualizerSliderPrivate { + SkinPixmapId skin_index; + gboolean scaled; + gint position; + gint width, height; + gboolean pressed; + gint drag_y; + gfloat value; /* store gain as is to prevent truncation --asphyx */ +}; + +static void ui_skinned_equalizer_slider_class_init (UiSkinnedEqualizerSliderClass *klass); +static void ui_skinned_equalizer_slider_init (UiSkinnedEqualizerSlider *equalizer_slider); +static void ui_skinned_equalizer_slider_destroy (GtkObject *object); +static void ui_skinned_equalizer_slider_realize (GtkWidget *widget); +static void ui_skinned_equalizer_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_equalizer_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_equalizer_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_equalizer_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_equalizer_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_equalizer_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static gboolean ui_skinned_equalizer_slider_scroll (GtkWidget *widget, GdkEventScroll *event); +static void ui_skinned_equalizer_slider_toggle_scaled (UiSkinnedEqualizerSlider *equalizer_slider); +void ui_skinned_equalizer_slider_set_mainwin_text (UiSkinnedEqualizerSlider * es); + +static GtkWidgetClass *parent_class = NULL; +static guint equalizer_slider_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_equalizer_slider_get_type() { + static GType equalizer_slider_type = 0; + if (!equalizer_slider_type) { + static const GTypeInfo equalizer_slider_info = { + sizeof (UiSkinnedEqualizerSliderClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_equalizer_slider_class_init, + NULL, + NULL, + sizeof (UiSkinnedEqualizerSlider), + 0, + (GInstanceInitFunc) ui_skinned_equalizer_slider_init, + }; + equalizer_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedEqualizerSlider", &equalizer_slider_info, 0); + } + + return equalizer_slider_type; +} + +static void ui_skinned_equalizer_slider_class_init(UiSkinnedEqualizerSliderClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_equalizer_slider_destroy; + + widget_class->realize = ui_skinned_equalizer_slider_realize; + widget_class->expose_event = ui_skinned_equalizer_slider_expose; + widget_class->size_request = ui_skinned_equalizer_slider_size_request; + widget_class->size_allocate = ui_skinned_equalizer_slider_size_allocate; + widget_class->button_press_event = ui_skinned_equalizer_slider_button_press; + widget_class->button_release_event = ui_skinned_equalizer_slider_button_release; + widget_class->motion_notify_event = ui_skinned_equalizer_slider_motion_notify; + widget_class->scroll_event = ui_skinned_equalizer_slider_scroll; + + klass->scaled = ui_skinned_equalizer_slider_toggle_scaled; + + equalizer_slider_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedEqualizerSliderClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedEqualizerSliderPrivate)); +} + +static void ui_skinned_equalizer_slider_init(UiSkinnedEqualizerSlider *equalizer_slider) { + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); + priv->pressed = FALSE; +} + +GtkWidget* ui_skinned_equalizer_slider_new(GtkWidget *fixed, gint x, gint y) { + UiSkinnedEqualizerSlider *es = g_object_new (ui_skinned_equalizer_slider_get_type (), NULL); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); + + es->x = x; + es->y = y; + priv->width = 14; + priv->height = 63; + priv->skin_index = SKIN_EQMAIN; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(es), es->x, es->y); + + return GTK_WIDGET(es); +} + +static void ui_skinned_equalizer_slider_destroy(GtkObject *object) { + UiSkinnedEqualizerSlider *equalizer_slider; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (object)); + + equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_equalizer_slider_realize(GtkWidget *widget) { + UiSkinnedEqualizerSlider *equalizer_slider; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_equalizer_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + requisition->width = priv->width*(priv->scaled ? config.scale_factor : 1); + requisition->height = priv->height*(priv->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_equalizer_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedEqualizerSlider *equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER (widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); + + widget->allocation = *allocation; + widget->allocation.x *= (priv->scaled ? config.scale_factor : 1); + widget->allocation.y *= (priv->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + equalizer_slider->x = widget->allocation.x/(priv->scaled ? config.scale_factor : 1); + equalizer_slider->y = widget->allocation.y/(priv->scaled ? config.scale_factor : 1); +} + +static gboolean ui_skinned_equalizer_slider_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER (widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); + + gint frame; + frame = 27 - ((priv->position * 27) / 50); + if (frame < 14) + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, (frame * 15) + 13, 164, 0, 0, priv->width, priv->height); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, ((frame - 14) * 15) + 13, 229, 0, 0, priv->width, priv->height); + + if (priv->pressed) + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, 0, 176, 1, priv->position, 11, 11); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, 0, 164, 1, priv->position, 11, 11); + + ui_skinned_widget_draw(widget, obj, priv->width, priv->height, priv->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static gboolean ui_skinned_equalizer_slider_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER (widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); + + gint y; + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + priv->pressed = TRUE; + y = event->y/(priv->scaled ? config.scale_factor : 1); + + if (y >= priv->position && y < priv->position + 11) + priv->drag_y = y - priv->position; + else { + priv->position = y - 5; + priv->drag_y = 5; + if (priv->position < 0) + priv->position = 0; + if (priv->position > 50) + priv->position = 50; + if (priv->position >= 24 && priv->position <= 26) + priv->position = 25; + + priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); +#if 0 + equalizerwin_eq_changed(); +#endif + } + + ui_skinned_equalizer_slider_set_mainwin_text(es); + gtk_widget_queue_draw(widget); + } + } + + return TRUE; +} + +static gboolean ui_skinned_equalizer_slider_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (event->button == 1) { + priv->pressed = FALSE; + mainwin_release_info_text(); + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_equalizer_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER(widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (priv->pressed) { + gint y; + + y = event->y/(priv->scaled ? config.scale_factor : 1); + priv->position = y - priv->drag_y; + + if (priv->position < 0) + priv->position = 0; + if (priv->position > 50) + priv->position = 50; + if (priv->position >= 24 && priv->position <= 26) + priv->position = 25; + + priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); + ui_skinned_equalizer_slider_set_mainwin_text(es); +#if 0 + equalizerwin_eq_changed(); +#endif + gtk_widget_queue_draw(widget); + } + + return TRUE; +} + +static gboolean ui_skinned_equalizer_slider_scroll(GtkWidget *widget, GdkEventScroll *event) { + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (event->direction == GDK_SCROLL_UP) { + priv->position -= 2; + + if (priv->position < 0) + priv->position = 0; + } + else { + priv->position += 2; + + if (priv->position > 50) + priv->position = 50; + } + + priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); +#if 0 + equalizerwin_eq_changed(); +#endif + gtk_widget_queue_draw(widget); + return TRUE; +} + +static void ui_skinned_equalizer_slider_toggle_scaled(UiSkinnedEqualizerSlider *equalizer_slider) { + GtkWidget *widget = GTK_WIDGET (equalizer_slider); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); + + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, priv->width*(priv->scaled ? config.scale_factor : 1), + priv->height*(priv->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(equalizer_slider)); +} + +void ui_skinned_equalizer_slider_set_position(GtkWidget *widget, gfloat pos) { + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget)); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (priv->pressed) + return; + + priv->value = (pos > EQUALIZER_MAX_GAIN) ? EQUALIZER_MAX_GAIN : ((pos < -EQUALIZER_MAX_GAIN) ? -EQUALIZER_MAX_GAIN : pos); + priv->position = 25 - (gint) ((pos * 25.0) / EQUALIZER_MAX_GAIN); + + if (priv->position < 0) + priv->position = 0; + + if (priv->position > 50) + priv->position = 50; + + if (priv->position >= 24 && priv->position <= 26) + priv->position = 25; + + gtk_widget_queue_draw(widget); +} + +gfloat ui_skinned_equalizer_slider_get_position(GtkWidget *widget) { + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), -1); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + return priv->value; +} + +void ui_skinned_equalizer_slider_set_mainwin_text(UiSkinnedEqualizerSlider * es) { + gint band = 0; + const gchar *bandname[11] = { N_("PREAMP"), N_("60HZ"), N_("170HZ"), + N_("310HZ"), N_("600HZ"), N_("1KHZ"), + N_("3KHZ"), N_("6KHZ"), N_("12KHZ"), + N_("14KHZ"), N_("16KHZ") + }; + gchar *tmp; + + if (es->x > 21) + band = ((es->x - 78) / 18) + 1; + + tmp = + g_strdup_printf("EQ: %s: %+.1f DB", _(bandname[band]), + ui_skinned_equalizer_slider_get_position(GTK_WIDGET(es))); + mainwin_lock_info_text(tmp); + g_free(tmp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_equalizer_slider.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,62 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses>. + */ + +#ifndef AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H +#define AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define EQUALIZER_MAX_GAIN 12.0 + +#define UI_SKINNED_EQUALIZER_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_equalizer_slider_get_type (), UiSkinnedEqualizerSlider) +#define UI_SKINNED_EQUALIZER_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_equalizer_slider_get_type (), UiSkinnedEqualizerSliderClass) +#define UI_SKINNED_IS_EQUALIZER_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_equalizer_slider_get_type ()) + +typedef struct _UiSkinnedEqualizerSlider UiSkinnedEqualizerSlider; +typedef struct _UiSkinnedEqualizerSliderClass UiSkinnedEqualizerSliderClass; + +struct _UiSkinnedEqualizerSlider { + GtkWidget widget; + gint x, y; +}; + +struct _UiSkinnedEqualizerSliderClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedEqualizerSlider *equalizer_slider); +}; + +GtkWidget* ui_skinned_equalizer_slider_new(GtkWidget *fixed, gint x, gint y); +GtkType ui_skinned_equalizer_slider_get_type(void); +void ui_skinned_equalizer_slider_set_position(GtkWidget *widget, gfloat pos); +gfloat ui_skinned_equalizer_slider_get_position(GtkWidget *widget); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_horizontal_slider.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,386 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skinned_horizontal_slider.h" +#include "skins_cfg.h" +#include <math.h> + +#define UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_horizontal_slider_get_type(), UiSkinnedHorizontalSliderPrivate)) +typedef struct _UiSkinnedHorizontalSliderPrivate UiSkinnedHorizontalSliderPrivate; + +enum { + MOTION, + RELEASE, + DOUBLED, + LAST_SIGNAL +}; + +struct _UiSkinnedHorizontalSliderPrivate { + SkinPixmapId skin_index; + gboolean scaled; + gint frame, frame_offset, frame_height, min, max; + gint knob_width, knob_height; + gint position; + gint width, height; + gint (*frame_cb) (gint); +}; + +static void ui_skinned_horizontal_slider_class_init (UiSkinnedHorizontalSliderClass *klass); +static void ui_skinned_horizontal_slider_init (UiSkinnedHorizontalSlider *horizontal_slider); +static void ui_skinned_horizontal_slider_destroy (GtkObject *object); +static void ui_skinned_horizontal_slider_realize (GtkWidget *widget); +static void ui_skinned_horizontal_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_horizontal_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_horizontal_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_horizontal_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_horizontal_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_horizontal_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_horizontal_slider_toggle_scaled (UiSkinnedHorizontalSlider *horizontal_slider); + +static GtkWidgetClass *parent_class = NULL; +static guint horizontal_slider_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_horizontal_slider_get_type() { + static GType horizontal_slider_type = 0; + if (!horizontal_slider_type) { + static const GTypeInfo horizontal_slider_info = { + sizeof (UiSkinnedHorizontalSliderClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_horizontal_slider_class_init, + NULL, + NULL, + sizeof (UiSkinnedHorizontalSlider), + 0, + (GInstanceInitFunc) ui_skinned_horizontal_slider_init, + }; + horizontal_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedHorizontalSlider", &horizontal_slider_info, 0); + } + + return horizontal_slider_type; +} + +static void ui_skinned_horizontal_slider_class_init(UiSkinnedHorizontalSliderClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_horizontal_slider_destroy; + + widget_class->realize = ui_skinned_horizontal_slider_realize; + widget_class->expose_event = ui_skinned_horizontal_slider_expose; + widget_class->size_request = ui_skinned_horizontal_slider_size_request; + widget_class->size_allocate = ui_skinned_horizontal_slider_size_allocate; + widget_class->button_press_event = ui_skinned_horizontal_slider_button_press; + widget_class->button_release_event = ui_skinned_horizontal_slider_button_release; + widget_class->motion_notify_event = ui_skinned_horizontal_slider_motion_notify; + + klass->motion = NULL; + klass->release = NULL; + klass->scaled = ui_skinned_horizontal_slider_toggle_scaled; + + horizontal_slider_signals[MOTION] = + g_signal_new ("motion", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, motion), NULL, NULL, + gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + horizontal_slider_signals[RELEASE] = + g_signal_new ("release", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, release), NULL, NULL, + gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + horizontal_slider_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedHorizontalSliderPrivate)); +} + +static void ui_skinned_horizontal_slider_init(UiSkinnedHorizontalSlider *horizontal_slider) { + horizontal_slider->pressed = FALSE; +} + +GtkWidget* ui_skinned_horizontal_slider_new(GtkWidget *fixed, gint x, gint y, gint w, gint h, gint knx, gint kny, + gint kpx, gint kpy, gint kw, gint kh, gint fh, + gint fo, gint min, gint max, gint(*fcb) (gint), SkinPixmapId si) { + + UiSkinnedHorizontalSlider *hs = g_object_new (ui_skinned_horizontal_slider_get_type (), NULL); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); + + hs->x = x; + hs->y = y; + priv->width = w; + priv->height = h; + hs->knob_nx = knx; + hs->knob_ny = kny; + hs->knob_px = kpx; + hs->knob_py = kpy; + priv->knob_width = kw; + priv->knob_height = kh; + priv->frame_height = fh; + priv->frame_offset = fo; + priv->min = min; + priv->position = min; + priv->max = max; + priv->frame_cb = fcb; + if (priv->frame_cb) + priv->frame = priv->frame_cb(0); + priv->skin_index = si; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); + + return GTK_WIDGET(hs); +} + +static void ui_skinned_horizontal_slider_destroy(GtkObject *object) { + UiSkinnedHorizontalSlider *horizontal_slider; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (object)); + + horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_horizontal_slider_realize(GtkWidget *widget) { + UiSkinnedHorizontalSlider *horizontal_slider; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_horizontal_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + requisition->width = priv->width*(priv->scaled ? config.scale_factor : 1); + requisition->height = priv->height*(priv->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_horizontal_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedHorizontalSlider *horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER (widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(horizontal_slider); + + widget->allocation = *allocation; + widget->allocation.x = ceil(widget->allocation.x*(priv->scaled ? config.scale_factor : 1)); + widget->allocation.y = ceil(widget->allocation.y*(priv->scaled ? config.scale_factor : 1)); + + if (priv->knob_height == priv->height) + priv->knob_height = ceil(allocation->height/(priv->scaled ? config.scale_factor : 1)); + priv->width = ceil(allocation->width/(priv->scaled ? config.scale_factor : 1)); + priv->height = ceil(allocation->height/(priv->scaled ? config.scale_factor : 1)); + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + horizontal_slider->x = ceil(widget->allocation.x/(priv->scaled ? config.scale_factor : 1)); + horizontal_slider->y = ceil(widget->allocation.y/(priv->scaled ? config.scale_factor : 1)); +} + +static gboolean ui_skinned_horizontal_slider_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER (widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + + if (priv->position > priv->max) priv->position = priv->max; + else if (priv->position < priv->min) priv->position = priv->min; + + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); + + skin_draw_pixbuf(widget, aud_active_skin, obj, + priv->skin_index, priv->frame_offset, + priv->frame * priv->frame_height, + 0, 0, priv->width, priv->height); + if (hs->pressed) + skin_draw_pixbuf(widget, aud_active_skin, obj, + priv->skin_index, hs->knob_px, + hs->knob_py, priv->position, + ((priv->height - priv->knob_height) / 2), + priv->knob_width, priv->knob_height); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, + priv->skin_index, hs->knob_nx, + hs->knob_ny, priv->position, + ((priv->height - priv->knob_height) / 2), + priv->knob_width, priv->knob_height); + + ui_skinned_widget_draw(widget, obj, priv->width, priv->height, priv->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static gboolean ui_skinned_horizontal_slider_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER (widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + gint x; + + x = event->x - (priv->knob_width / (priv->scaled ? 1 : config.scale_factor)); + hs->pressed = TRUE; + + priv->position = x/(priv->scaled ? config.scale_factor : 1); + if (priv->position < priv->min) + priv->position = priv->min; + if (priv->position > priv->max) + priv->position = priv->max; + if (priv->frame_cb) + priv->frame = priv->frame_cb(priv->position); + + g_signal_emit_by_name(widget, "motion", priv->position); + gtk_widget_queue_draw(widget); + } else if (event->button == 3) { + if (hs->pressed) { + hs->pressed = FALSE; + g_signal_emit_by_name(widget, "release", priv->position); + gtk_widget_queue_draw(widget); + } + event->x = event->x + hs->x; + event->y = event->y + hs->y; + return FALSE; + } + } + return TRUE; +} + +static gboolean ui_skinned_horizontal_slider_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + if (hs->pressed) { + hs->pressed = FALSE; + g_signal_emit_by_name(widget, "release", priv->position); + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_horizontal_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + if (hs->pressed) { + gint x; + + x = event->x - (priv->knob_width / (priv->scaled ? 1 : config.scale_factor)); + priv->position = x/(priv->scaled ? config.scale_factor : 1); + + if (priv->position < priv->min) + priv->position = priv->min; + + if (priv->position > priv->max) + priv->position = priv->max; + + if (priv->frame_cb) + priv->frame = priv->frame_cb(priv->position); + + g_signal_emit_by_name(widget, "motion", priv->position); + gtk_widget_queue_draw(widget); + } + + return TRUE; +} + +static void ui_skinned_horizontal_slider_toggle_scaled(UiSkinnedHorizontalSlider *horizontal_slider) { + GtkWidget *widget = GTK_WIDGET (horizontal_slider); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(horizontal_slider); + + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, + priv->width*(priv->scaled ? config.scale_factor : 1), + priv->height*(priv->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(horizontal_slider)); +} + +void ui_skinned_horizontal_slider_set_position(GtkWidget *widget, gint pos) { + g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget)); + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + if (pos == priv->position || hs->pressed) + return; + + priv->position = pos; + + if (priv->frame_cb) + priv->frame = priv->frame_cb(priv->position); + + gtk_widget_queue_draw(widget); +} + +gint ui_skinned_horizontal_slider_get_position(GtkWidget *widget) { + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), -1); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + return priv->position; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_horizontal_slider.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,69 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H +#define AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_HORIZONTAL_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_horizontal_slider_get_type (), UiSkinnedHorizontalSlider) +#define UI_SKINNED_HORIZONTAL_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_horizontal_slider_get_type (), UiSkinnedHorizontalSliderClass) +#define UI_SKINNED_IS_HORIZONTAL_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_horizontal_slider_get_type ()) + +typedef struct _UiSkinnedHorizontalSlider UiSkinnedHorizontalSlider; +typedef struct _UiSkinnedHorizontalSliderClass UiSkinnedHorizontalSliderClass; + +struct _UiSkinnedHorizontalSlider { + GtkWidget widget; + gboolean pressed; + gint x, y; + gint knob_nx, knob_ny, knob_px, knob_py; +}; + +struct _UiSkinnedHorizontalSliderClass { + GtkWidgetClass parent_class; + void (* motion) (UiSkinnedHorizontalSlider *horizontal_slider); + void (* release) (UiSkinnedHorizontalSlider *horizontal_slider); + void (* scaled) (UiSkinnedHorizontalSlider *horizontal_slider); + void (* redraw) (UiSkinnedHorizontalSlider *horizontal_slider); +}; +GtkWidget* ui_skinned_horizontal_slider_new(GtkWidget *fixed, gint x, gint y, gint w, gint h, gint knx, gint kny, + gint kpx, gint kpy, gint kw, gint kh, gint fh, + gint fo, gint min, gint max, gint(*fcb) (gint), SkinPixmapId si); +GtkType ui_skinned_horizontal_slider_get_type(void); +void ui_skinned_horizontal_slider_set_position(GtkWidget *widget, gint pos); +gint ui_skinned_horizontal_slider_get_position(GtkWidget *widget); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_menurow.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,332 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include <audacious/plugin.h> +#include "plugin.h" +#include "ui_skinned_menurow.h" + +enum { + DOUBLED, + CHANGE, + RELEASE, + LAST_SIGNAL +}; + +static void ui_skinned_menurow_class_init (UiSkinnedMenurowClass *klass); +static void ui_skinned_menurow_init (UiSkinnedMenurow *menurow); +static void ui_skinned_menurow_destroy (GtkObject *object); +static void ui_skinned_menurow_realize (GtkWidget *widget); +static void ui_skinned_menurow_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_menurow_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_menurow_expose (GtkWidget *widget, GdkEventExpose *event); +static MenuRowItem menurow_find_selected (UiSkinnedMenurow * mr, gint x, gint y); +static gboolean ui_skinned_menurow_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_menurow_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_menurow_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_menurow_toggle_scaled (UiSkinnedMenurow *menurow); + +static GtkWidgetClass *parent_class = NULL; +static guint menurow_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_menurow_get_type() { + static GType menurow_type = 0; + if (!menurow_type) { + static const GTypeInfo menurow_info = { + sizeof (UiSkinnedMenurowClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_menurow_class_init, + NULL, + NULL, + sizeof (UiSkinnedMenurow), + 0, + (GInstanceInitFunc) ui_skinned_menurow_init, + }; + menurow_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedMenurow", &menurow_info, 0); + } + + return menurow_type; +} + +static void ui_skinned_menurow_class_init(UiSkinnedMenurowClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_menurow_destroy; + + widget_class->realize = ui_skinned_menurow_realize; + widget_class->expose_event = ui_skinned_menurow_expose; + widget_class->size_request = ui_skinned_menurow_size_request; + widget_class->size_allocate = ui_skinned_menurow_size_allocate; + widget_class->button_press_event = ui_skinned_menurow_button_press; + widget_class->button_release_event = ui_skinned_menurow_button_release; + widget_class->motion_notify_event = ui_skinned_menurow_motion_notify; + + klass->scaled = ui_skinned_menurow_toggle_scaled; + klass->change = NULL; + klass->release = NULL; + + menurow_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMenurowClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + + menurow_signals[CHANGE] = + g_signal_new ("change", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMenurowClass, change), NULL, NULL, + gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + menurow_signals[RELEASE] = + g_signal_new ("release", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMenurowClass, release), NULL, NULL, + g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER); + +} + +static void ui_skinned_menurow_init(UiSkinnedMenurow *menurow) { + menurow->scale_selected = config.scaled; + menurow->always_selected = config.always_on_top; +} + +GtkWidget* ui_skinned_menurow_new(GtkWidget *fixed, gint x, gint y, gint nx, gint ny, gint sx, gint sy, SkinPixmapId si) { + UiSkinnedMenurow *menurow = g_object_new (ui_skinned_menurow_get_type (), NULL); + + menurow->x = x; + menurow->y = y; + menurow->width = 8; + menurow->height = 43; + menurow->nx = nx; + menurow->ny = ny; + menurow->sx = sx; + menurow->sy = sy; + menurow->selected = MENUROW_NONE; + + menurow->skin_index = si; + + menurow->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(menurow), menurow->x, menurow->y); + + return GTK_WIDGET(menurow); +} + +static void ui_skinned_menurow_destroy(GtkObject *object) { + UiSkinnedMenurow *menurow; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_MENUROW (object)); + + menurow = UI_SKINNED_MENUROW (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_menurow_realize(GtkWidget *widget) { + UiSkinnedMenurow *menurow; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_MENUROW(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + menurow = UI_SKINNED_MENUROW(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_menurow_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); + + requisition->width = menurow->width*(menurow->scaled ? config.scale_factor : 1); + requisition->height = menurow->height*(menurow->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_menurow_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (menurow->scaled ? config.scale_factor : 1); + widget->allocation.y *= (menurow->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + menurow->x = widget->allocation.x/(menurow->scaled ? config.scale_factor : 1); + menurow->y = widget->allocation.y/(menurow->scaled ? config.scale_factor : 1); +} + +static gboolean ui_skinned_menurow_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); + g_return_val_if_fail (menurow->width > 0 && menurow->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, menurow->width, menurow->height); + + if (menurow->selected == MENUROW_NONE) { + if (config.always_show_cb || menurow->pushed) + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->nx, menurow->ny, 0, 0, 8, 43); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->nx + 8, menurow->ny, 0, 0, 8, 43); + } + else { + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->sx + ((menurow->selected - 1) * 8), + menurow->sy, 0, 0, 8, 43); + } + if (config.always_show_cb || menurow->pushed) { + if (menurow->always_selected) + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->sx + 8, menurow->sy + 10, 0, 10, 8, 8); + if (menurow->scale_selected) + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->sx + 24, menurow->sy + 26, 0, 26, 8, 8); + } + + ui_skinned_widget_draw(widget, obj, menurow->width, menurow->height, menurow->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static MenuRowItem menurow_find_selected(UiSkinnedMenurow * mr, gint x, gint y) { + MenuRowItem ret = MENUROW_NONE; + + x = x/(mr->scaled ? config.scale_factor : 1); + y = y/(mr->scaled ? config.scale_factor : 1); + if (x > 0 && x < 8) { + if (y >= 0 && y <= 10) + ret = MENUROW_OPTIONS; + if (y >= 10 && y <= 17) + ret = MENUROW_ALWAYS; + if (y >= 18 && y <= 25) + ret = MENUROW_FILEINFOBOX; + if (y >= 26 && y <= 33) + ret = MENUROW_SCALE; + if (y >= 34 && y <= 42) + ret = MENUROW_VISUALIZATION; + } + return ret; +} + +static gboolean ui_skinned_menurow_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + + menurow->pushed = TRUE; + menurow->selected = menurow_find_selected(menurow, event->x, event->y); + + gtk_widget_queue_draw(widget); + g_signal_emit_by_name(widget, "change", menurow->selected); + } + } + + return TRUE; +} + +static gboolean ui_skinned_menurow_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); + if (menurow->pushed) { + menurow->pushed = FALSE; + + if (menurow->selected == MENUROW_ALWAYS) + menurow->always_selected = !menurow->always_selected; + + if (menurow->selected == MENUROW_SCALE) + menurow->scale_selected = !menurow->scale_selected; + + if ((int)(menurow->selected) != -1) + g_signal_emit_by_name(widget, "release", menurow->selected, event); + + menurow->selected = MENUROW_NONE; + gtk_widget_queue_draw(widget); + } + + return TRUE; +} + +static gboolean ui_skinned_menurow_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); + + if (menurow->pushed) { + menurow->selected = menurow_find_selected(menurow, event->x, event->y); + + gtk_widget_queue_draw(widget); + g_signal_emit_by_name(widget, "change", menurow->selected); + } + + return TRUE; +} + +static void ui_skinned_menurow_toggle_scaled(UiSkinnedMenurow *menurow) { + GtkWidget *widget = GTK_WIDGET (menurow); + + menurow->scaled = !menurow->scaled; + gtk_widget_set_size_request(widget, menurow->width* (menurow->scaled ? config.scale_factor : 1), + menurow->height * (menurow->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(menurow)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_menurow.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,77 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_MENUROW_H +#define AUDACIOUS_UI_SKINNED_MENUROW_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_MENUROW(obj) GTK_CHECK_CAST (obj, ui_skinned_menurow_get_type (), UiSkinnedMenurow) +#define UI_SKINNED_MENUROW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_menurow_get_type (), UiSkinnedMenurowClass) +#define UI_SKINNED_IS_MENUROW(obj) GTK_CHECK_TYPE (obj, ui_skinned_menurow_get_type ()) + +typedef struct _UiSkinnedMenurow UiSkinnedMenurow; +typedef struct _UiSkinnedMenurowClass UiSkinnedMenurowClass; + +typedef enum { + MENUROW_NONE, MENUROW_OPTIONS, MENUROW_ALWAYS, MENUROW_FILEINFOBOX, + MENUROW_SCALE, MENUROW_VISUALIZATION +} MenuRowItem; + +struct _UiSkinnedMenurow { + GtkWidget widget; + + gint x, y, width, height; + gboolean scaled; + gint nx, ny; + gint sx, sy; + MenuRowItem selected; + gboolean always_selected; + gboolean scale_selected; + gboolean pushed; + SkinPixmapId skin_index; +}; + +struct _UiSkinnedMenurowClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedMenurow *menurow); + void (* change) (UiSkinnedMenurow *menurow); + void (* release) (UiSkinnedMenurow *menurow); +}; + +GtkWidget* ui_skinned_menurow_new (GtkWidget *fixed, gint x, gint y, gint nx, gint ny, gint sx, gint sy, SkinPixmapId si); +GtkType ui_skinned_menurow_get_type(void); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_MENUROW_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_monostereo.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,222 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skin.h" +#include "ui_skinned_monostereo.h" +#include "skins_cfg.h" + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_monostereo_class_init (UiSkinnedMonoStereoClass *klass); +static void ui_skinned_monostereo_init (UiSkinnedMonoStereo *monostereo); +static void ui_skinned_monostereo_destroy (GtkObject *object); +static void ui_skinned_monostereo_realize (GtkWidget *widget); +static void ui_skinned_monostereo_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_monostereo_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_monostereo_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_monostereo_toggle_scaled (UiSkinnedMonoStereo *monostereo); + +static GtkWidgetClass *parent_class = NULL; +static guint monostereo_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_monostereo_get_type() { + static GType monostereo_type = 0; + if (!monostereo_type) { + static const GTypeInfo monostereo_info = { + sizeof (UiSkinnedMonoStereoClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_monostereo_class_init, + NULL, + NULL, + sizeof (UiSkinnedMonoStereo), + 0, + (GInstanceInitFunc) ui_skinned_monostereo_init, + }; + monostereo_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedMonoStereo", &monostereo_info, 0); + } + + return monostereo_type; +} + +static void ui_skinned_monostereo_class_init(UiSkinnedMonoStereoClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_monostereo_destroy; + + widget_class->realize = ui_skinned_monostereo_realize; + widget_class->expose_event = ui_skinned_monostereo_expose; + widget_class->size_request = ui_skinned_monostereo_size_request; + widget_class->size_allocate = ui_skinned_monostereo_size_allocate; + + klass->scaled = ui_skinned_monostereo_toggle_scaled; + + monostereo_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMonoStereoClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_monostereo_init(UiSkinnedMonoStereo *monostereo) { + monostereo->width = 56; + monostereo->height = 12; +} + +GtkWidget* ui_skinned_monostereo_new(GtkWidget *fixed, gint x, gint y, SkinPixmapId si) { + UiSkinnedMonoStereo *monostereo = g_object_new (ui_skinned_monostereo_get_type (), NULL); + + monostereo->x = x; + monostereo->y = y; + monostereo->skin_index = si; + monostereo->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(monostereo), monostereo->x, monostereo->y); + + return GTK_WIDGET(monostereo); +} + +static void ui_skinned_monostereo_destroy(GtkObject *object) { + UiSkinnedMonoStereo *monostereo; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_MONOSTEREO (object)); + + monostereo = UI_SKINNED_MONOSTEREO (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_monostereo_realize(GtkWidget *widget) { + UiSkinnedMonoStereo *monostereo; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_MONOSTEREO(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + monostereo = UI_SKINNED_MONOSTEREO(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_monostereo_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO(widget); + + requisition->width = monostereo->width*(monostereo->scaled ? config.scale_factor : 1); + requisition->height = monostereo->height*(monostereo->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_monostereo_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (monostereo->scaled ? config.scale_factor : 1); + widget->allocation.y *= (monostereo->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + monostereo->x = widget->allocation.x/(monostereo->scaled ? config.scale_factor : 1); + monostereo->y = widget->allocation.y/(monostereo->scaled ? config.scale_factor : 1); +} + +static gboolean ui_skinned_monostereo_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MONOSTEREO (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); + g_return_val_if_fail (monostereo->width > 0 && monostereo->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, monostereo->width, monostereo->height); + + switch (monostereo->num_channels) { + case 1: + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 0, 0, 0, 27, 12); + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 12, 27, 0, 29, 12); + break; + case 2: + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 12, 0, 0, 27, 12); + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 0, 27, 0, 29, 12); + break; + default: + case 0: + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 12, 0, 0, 27, 12); + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 12, 27, 0, 29, 12); + break; + } + + ui_skinned_widget_draw(widget, obj, monostereo->width, monostereo->height, monostereo->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_monostereo_toggle_scaled(UiSkinnedMonoStereo *monostereo) { + GtkWidget *widget = GTK_WIDGET (monostereo); + + monostereo->scaled = !monostereo->scaled; + gtk_widget_set_size_request(widget, monostereo->width*(monostereo->scaled ? config.scale_factor : 1), monostereo->height*(monostereo->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(monostereo)); +} + +void ui_skinned_monostereo_set_num_channels(GtkWidget *widget, gint nch) { + g_return_if_fail (UI_SKINNED_IS_MONOSTEREO (widget)); + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); + + monostereo->num_channels = nch; + gtk_widget_queue_draw(widget); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_monostereo.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,66 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_MONOSTEREO_H +#define AUDACIOUS_UI_SKINNED_MONOSTEREO_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_MONOSTEREO(obj) GTK_CHECK_CAST (obj, ui_skinned_monostereo_get_type (), UiSkinnedMonoStereo) +#define UI_SKINNED_MONOSTEREO_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_monostereo_get_type (), UiSkinnedMonoStereoClass) +#define UI_SKINNED_IS_MONOSTEREO(obj) GTK_CHECK_TYPE (obj, ui_skinned_monostereo_get_type ()) + +typedef struct _UiSkinnedMonoStereo UiSkinnedMonoStereo; +typedef struct _UiSkinnedMonoStereoClass UiSkinnedMonoStereoClass; + +struct _UiSkinnedMonoStereo { + GtkWidget widget; + + gint x, y, width, height; + gint num_channels; + SkinPixmapId skin_index; + gboolean scaled; +}; + +struct _UiSkinnedMonoStereoClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedMonoStereo *menurow); +}; + +GtkWidget* ui_skinned_monostereo_new (GtkWidget *fixed, gint x, gint y, SkinPixmapId si); +GtkType ui_skinned_monostereo_get_type(void); +void ui_skinned_monostereo_set_num_channels(GtkWidget *widget, gint nch); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_MONOSTEREO_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_number.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,234 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skinned_number.h" +#include "skins_cfg.h" +#include "strings.h" +#include <string.h> +#include <ctype.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkmarshal.h> + +#define UI_TYPE_SKINNED_NUMBER (ui_skinned_number_get_type()) + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_number_class_init (UiSkinnedNumberClass *klass); +static void ui_skinned_number_init (UiSkinnedNumber *number); +static void ui_skinned_number_destroy (GtkObject *object); +static void ui_skinned_number_realize (GtkWidget *widget); +static void ui_skinned_number_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_number_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_number_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_number_toggle_scaled (UiSkinnedNumber *number); + +static GtkWidgetClass *parent_class = NULL; +static guint number_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_number_get_type() { + static GType number_type = 0; + if (!number_type) { + static const GTypeInfo number_info = { + sizeof (UiSkinnedNumberClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_number_class_init, + NULL, + NULL, + sizeof (UiSkinnedNumber), + 0, + (GInstanceInitFunc) ui_skinned_number_init, + }; + number_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedNumber", &number_info, 0); + } + + return number_type; +} + +static void ui_skinned_number_class_init(UiSkinnedNumberClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_number_destroy; + + widget_class->realize = ui_skinned_number_realize; + widget_class->expose_event = ui_skinned_number_expose; + widget_class->size_request = ui_skinned_number_size_request; + widget_class->size_allocate = ui_skinned_number_size_allocate; + + klass->scaled = ui_skinned_number_toggle_scaled; + + number_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedNumberClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_number_init(UiSkinnedNumber *number) { + number->width = 9; + number->height = 13; +} + +GtkWidget* ui_skinned_number_new(GtkWidget *fixed, gint x, gint y, SkinPixmapId si) { + UiSkinnedNumber *number = g_object_new (ui_skinned_number_get_type (), NULL); + + number->x = x; + number->y = y; + number->num = 0; + number->skin_index = si; + + number->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(number), number->x, number->y); + + return GTK_WIDGET(number); +} + +static void ui_skinned_number_destroy(GtkObject *object) { + UiSkinnedNumber *number; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_NUMBER (object)); + + number = UI_SKINNED_NUMBER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_number_realize(GtkWidget *widget) { + UiSkinnedNumber *number; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_NUMBER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + number = UI_SKINNED_NUMBER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_number_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedNumber *number = UI_SKINNED_NUMBER(widget); + + requisition->width = number->width * ( number->scaled ? config.scale_factor : 1 ); + requisition->height = number->height*( number->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_number_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (number->scaled ? config.scale_factor: 1 ); + widget->allocation.y *= (number->scaled ? config.scale_factor: 1 ); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + number->x = widget->allocation.x/(number->scaled ? config.scale_factor : 1); + number->y = widget->allocation.y/(number->scaled ? config.scale_factor : 1); +} + +static gboolean ui_skinned_number_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_NUMBER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + g_return_val_if_fail (number->width > 0 && number->height > 0, FALSE); + + GdkPixbuf *obj; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, number->width, number->height); + + if (number->num > 11 || number->num < 0) + number->num = 10; + + skin_draw_pixbuf(widget, aud_active_skin, obj, + number->skin_index, number->num * 9, 0, + 0, 0, number->width, number->height); + + ui_skinned_widget_draw(widget, obj, number->width, number->height, number->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_number_toggle_scaled(UiSkinnedNumber *number) { + GtkWidget *widget = GTK_WIDGET (number); + number->scaled = !number->scaled; + + gtk_widget_set_size_request(widget, number->width * ( number->scaled ? config.scale_factor : 1), + number->height * ( number->scaled ? config.scale_factor : 1) ); + + gtk_widget_queue_draw(GTK_WIDGET(number)); +} + +void ui_skinned_number_set_number(GtkWidget *widget, gint num) { + g_return_if_fail(UI_SKINNED_IS_NUMBER(widget)); + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + + if (number->num == num) + return; + + number->num = num; + gtk_widget_queue_draw(GTK_WIDGET(number)); +} + +void ui_skinned_number_set_size(GtkWidget *widget, gint width, gint height) { + g_return_if_fail(UI_SKINNED_IS_NUMBER(widget)); + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + + number->width = width; + number->height = height; + + gtk_widget_set_size_request(widget, width*(number->scaled ? config.scale_factor : 1 ), + height*(number->scaled ? config.scale_factor : 1 )); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_number.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,61 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_NUMBER_H +#define AUDACIOUS_UI_SKINNED_NUMBER_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_NUMBER(obj) GTK_CHECK_CAST (obj, ui_skinned_number_get_type (), UiSkinnedNumber) +#define UI_SKINNED_NUMBER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_number_get_type (), UiSkinnedNumberClass) +#define UI_SKINNED_IS_NUMBER(obj) GTK_CHECK_TYPE (obj, ui_skinned_number_get_type ()) + +typedef struct _UiSkinnedNumber UiSkinnedNumber; +typedef struct _UiSkinnedNumberClass UiSkinnedNumberClass; + +struct _UiSkinnedNumber { + GtkWidget widget; + + gint x, y, width, height; + gint num; + gboolean scaled; + SkinPixmapId skin_index; +}; + +struct _UiSkinnedNumberClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedNumber *textbox); +}; + +GtkWidget* ui_skinned_number_new (GtkWidget *fixed, gint x, gint y, SkinPixmapId si); +GtkType ui_skinned_number_get_type(void); +void ui_skinned_number_set_number(GtkWidget *widget, gint num); +void ui_skinned_number_set_size(GtkWidget *widget, gint width, gint height); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_NUMBER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_playlist.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,1109 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * Copyright (c) 2008 William Pitcock + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +/* + * A note about Pango and some funky spacey fonts: Weirdly baselined + * fonts, or fonts with weird ascents or descents _will_ display a + * little bit weird in the playlist widget, but the display engine + * won't make it look too bad, just a little deranged. I honestly + * don't think it's worth fixing (around...), it doesn't have to be + * perfectly fitting, just the general look has to be ok, which it + * IMHO is. + * + * A second note: The numbers aren't perfectly aligned, but in the + * end it looks better when using a single Pango layout for each + * number. + */ + +#include "ui_skinned_playlist.h" + +#include "debug.h" +#if 0 +#include "ui_fileinfopopup.h" +#endif +#include "ui_playlist.h" +#include "ui_manager.h" +#include "ui_skin.h" +#include "util.h" +#include "skins_cfg.h" +#include <audacious/plugin.h> + +static PangoFontDescription *playlist_list_font = NULL; +static gint ascent, descent, width_delta_digit_one; +static gboolean has_slant; +static guint padding; + +/* FIXME: the following globals should not be needed. */ +static gint width_approx_letters; +static gint width_colon, width_colon_third; +static gint width_approx_digits, width_approx_digits_half; + +#define UI_SKINNED_PLAYLIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_playlist_get_type(), UiSkinnedPlaylistPrivate)) +typedef struct _UiSkinnedPlaylistPrivate UiSkinnedPlaylistPrivate; + +enum { + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedPlaylistPrivate { + SkinPixmapId skin_index; + gint width, height; + gint resize_width, resize_height; + gint drag_pos; + gboolean dragging, auto_drag_down, auto_drag_up; + gint auto_drag_up_tag, auto_drag_down_tag; +}; + +static void ui_skinned_playlist_class_init (UiSkinnedPlaylistClass *klass); +static void ui_skinned_playlist_init (UiSkinnedPlaylist *playlist); +static void ui_skinned_playlist_destroy (GtkObject *object); +static void ui_skinned_playlist_realize (GtkWidget *widget); +static void ui_skinned_playlist_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_playlist_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_playlist_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_playlist_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static gboolean ui_skinned_playlist_leave_notify (GtkWidget *widget, GdkEventCrossing *event); +static void ui_skinned_playlist_redraw (UiSkinnedPlaylist *playlist); +static gboolean ui_skinned_playlist_popup_show (gpointer data); +static void ui_skinned_playlist_popup_hide (GtkWidget *widget); +static void ui_skinned_playlist_popup_timer_start (GtkWidget *widget); +static void ui_skinned_playlist_popup_timer_stop (GtkWidget *widget); + +static GtkWidgetClass *parent_class = NULL; +static guint playlist_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_playlist_get_type() { + static GType playlist_type = 0; + if (!playlist_type) { + static const GTypeInfo playlist_info = { + sizeof (UiSkinnedPlaylistClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_playlist_class_init, + NULL, + NULL, + sizeof (UiSkinnedPlaylist), + 0, + (GInstanceInitFunc) ui_skinned_playlist_init, + }; + playlist_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaylist", &playlist_info, 0); + } + + return playlist_type; +} + +static void ui_skinned_playlist_class_init(UiSkinnedPlaylistClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_playlist_destroy; + + widget_class->realize = ui_skinned_playlist_realize; + widget_class->expose_event = ui_skinned_playlist_expose; + widget_class->size_request = ui_skinned_playlist_size_request; + widget_class->size_allocate = ui_skinned_playlist_size_allocate; + widget_class->button_press_event = ui_skinned_playlist_button_press; + widget_class->button_release_event = ui_skinned_playlist_button_release; + widget_class->motion_notify_event = ui_skinned_playlist_motion_notify; + widget_class->leave_notify_event = ui_skinned_playlist_leave_notify; + + klass->redraw = ui_skinned_playlist_redraw; + + playlist_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedPlaylistClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedPlaylistPrivate)); +} + +static void ui_skinned_playlist_init(UiSkinnedPlaylist *playlist) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); + playlist->pressed = FALSE; + priv->resize_width = 0; + priv->resize_height = 0; + playlist->prev_selected = -1; + playlist->prev_min = -1; + playlist->prev_max = -1; + + g_object_set_data(G_OBJECT(playlist), "timer_id", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(playlist), "timer_active", GINT_TO_POINTER(0)); +#if 0 + GtkWidget *popup = fileinfopopup_create(); + g_object_set_data(G_OBJECT(playlist), "popup", popup); + g_object_set_data(G_OBJECT(playlist), "popup_active", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(playlist), "popup_position", GINT_TO_POINTER(-1)); +#endif +} + +GtkWidget* ui_skinned_playlist_new(GtkWidget *fixed, gint x, gint y, gint w, gint h) { + + UiSkinnedPlaylist *hs = g_object_new (ui_skinned_playlist_get_type (), NULL); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(hs); + + hs->x = x; + hs->y = y; + priv->width = w; + priv->height = h; + priv->skin_index = SKIN_PLEDIT; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); + gtk_widget_set_double_buffered(GTK_WIDGET(hs), TRUE); + + return GTK_WIDGET(hs); +} + +static void ui_skinned_playlist_destroy(GtkObject *object) { + UiSkinnedPlaylist *playlist; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST (object)); + + playlist = UI_SKINNED_PLAYLIST (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_playlist_realize(GtkWidget *widget) { + UiSkinnedPlaylist *playlist; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + playlist = UI_SKINNED_PLAYLIST(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_playlist_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + requisition->width = priv->width; + requisition->height = priv->height; +} + +static void ui_skinned_playlist_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedPlaylist *playlist = UI_SKINNED_PLAYLIST (widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + playlist->x = widget->allocation.x; + playlist->y = widget->allocation.y; + + if (priv->height != widget->allocation.height || priv->width != widget->allocation.width) { + priv->width = priv->width + priv->resize_width; + priv->height = priv->height + priv->resize_height; + priv->resize_width = 0; + priv->resize_height = 0; + gtk_widget_queue_draw(widget); + } +} + +static gboolean ui_skinned_playlist_auto_drag_down_func(gpointer data) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(data); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(data); + + if (priv->auto_drag_down) { + ui_skinned_playlist_move_down(pl); + pl->first++; + playlistwin_update_list(aud_playlist_get_active()); + return TRUE; + } + return FALSE; +} + +static gboolean ui_skinned_playlist_auto_drag_up_func(gpointer data) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(data); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(data); + + if (priv->auto_drag_up) { + ui_skinned_playlist_move_up(pl); + pl->first--; + playlistwin_update_list(aud_playlist_get_active()); + return TRUE; + + } + return FALSE; +} + +void ui_skinned_playlist_move_up(UiSkinnedPlaylist * pl) { + GList *list; + Playlist *playlist = aud_playlist_get_active(); + + if (!playlist) + return; + + PLAYLIST_LOCK(playlist); + if ((list = playlist->entries) == NULL) { + PLAYLIST_UNLOCK(playlist); + return; + } + if (PLAYLIST_ENTRY(list->data)->selected) { + /* We are at the top */ + PLAYLIST_UNLOCK(playlist); + return; + } + while (list) { + if (PLAYLIST_ENTRY(list->data)->selected) + glist_moveup(list); + list = g_list_next(list); + } + PLAYLIST_INCR_SERIAL(playlist); + PLAYLIST_UNLOCK(playlist); + if (pl->prev_selected != -1) + pl->prev_selected--; + if (pl->prev_min != -1) + pl->prev_min--; + if (pl->prev_max != -1) + pl->prev_max--; +} + +void ui_skinned_playlist_move_down(UiSkinnedPlaylist * pl) { + GList *list; + Playlist *playlist = aud_playlist_get_active(); + + if (!playlist) + return; + + PLAYLIST_LOCK(playlist); + + if (!(list = g_list_last(playlist->entries))) { + PLAYLIST_UNLOCK(playlist); + return; + } + + if (PLAYLIST_ENTRY(list->data)->selected) { + /* We are at the bottom */ + PLAYLIST_UNLOCK(playlist); + return; + } + + while (list) { + if (PLAYLIST_ENTRY(list->data)->selected) + glist_movedown(list); + list = g_list_previous(list); + } + + PLAYLIST_INCR_SERIAL(playlist); + PLAYLIST_UNLOCK(playlist); + + if (pl->prev_selected != -1) + pl->prev_selected++; + if (pl->prev_min != -1) + pl->prev_min++; + if (pl->prev_max != -1) + pl->prev_max++; +} + +static void +playlist_list_draw_string(cairo_t *cr, UiSkinnedPlaylist *pl, + PangoFontDescription * font, + gint line, + gint width, + const gchar * text, + guint ppos) +{ + guint plist_length_int; + Playlist *playlist = aud_playlist_get_active(); + PangoLayout *layout; + + REQUIRE_LOCK(playlist->mutex); + + cairo_new_path(cr); + + if (config.show_numbers_in_pl) { + gchar *pos_string = g_strdup_printf(config.show_separator_in_pl == TRUE ? "%d" : "%d.", ppos); + plist_length_int = + gint_count_digits(aud_playlist_get_length(playlist)) + !config.show_separator_in_pl + 1; /* cf.show_separator_in_pl will be 0 if false */ + + padding = plist_length_int; + padding = ((padding + 1) * width_approx_digits); + + layout = gtk_widget_create_pango_layout(playlistwin, pos_string); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, plist_length_int * 100); + + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + + cairo_move_to(cr, (width_approx_digits * + (-1 + plist_length_int - strlen(pos_string))) + + (width_approx_digits / 4), (line - 1) * pl->fheight + + ascent + abs(descent)); + pango_cairo_show_layout(cr, layout); + + g_free(pos_string); + g_object_unref(layout); + + if (!config.show_separator_in_pl) + padding -= (width_approx_digits * 1.5); + } else { + padding = 3; + } + + width -= padding; + + layout = gtk_widget_create_pango_layout(playlistwin, text); + + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, width * PANGO_SCALE); + pango_layout_set_single_paragraph_mode(layout, TRUE); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + + cairo_move_to(cr, padding + (width_approx_letters / 4), + (line - 1) * pl->fheight + + ascent + abs(descent)); + pango_cairo_show_layout(cr, layout); + + g_object_unref(layout); +} + +static gboolean ui_skinned_playlist_expose(GtkWidget *widget, GdkEventExpose *event) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(pl); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + Playlist *playlist = aud_playlist_get_active(); + PlaylistEntry *entry; + GList *list; + PangoLayout *layout; + gchar *title; + gint width, height; + gint i, max_first; + guint padding, padding_dwidth, padding_plength; + guint max_time_len = 0; + gfloat queue_tailpadding = 0; + gint tpadding; + gsize tpadding_dwidth = 0; + gint x, y; + guint tail_width; + guint tail_len; + gboolean in_selection = FALSE; + + gchar tail[100]; + gchar queuepos[255]; + gchar length[40]; + + gchar **frags; + gchar *frag0; + + gint plw_w, plw_h; + + cairo_t *cr; + gint yc; + gint pos; + gdouble rounding_offset; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_PLAYLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + cr = gdk_cairo_create(widget->window); + + width = priv->width; + height = priv->height; + + plw_w = playlistwin_get_width(); + plw_h = playlistwin_get_height(); + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMALBG)); + + cairo_rectangle(cr, 0, 0, width, height); + cairo_paint(cr); + + if (!playlist_list_font) { + g_critical("Couldn't open playlist font"); + return FALSE; + } + + pl->fheight = (ascent + abs(descent)); + pl->num_visible = height / pl->fheight; + + rounding_offset = pl->fheight / 3; + + max_first = aud_playlist_get_length(playlist) - pl->num_visible; + max_first = MAX(max_first, 0); + + pl->first = CLAMP(pl->first, 0, max_first); + + PLAYLIST_LOCK(playlist); + list = playlist->entries; + list = g_list_nth(list, pl->first); + + /* It sucks having to run the iteration twice but this is the only + way you can reliably get the maximum width so we can get our + playlist nice and aligned... -- plasmaroo */ + + for (i = pl->first; + list && i < pl->first + pl->num_visible; + list = g_list_next(list), i++) { + entry = list->data; + + if (entry->length != -1) + { + g_snprintf(length, sizeof(length), "%d:%-2.2d", + entry->length / 60000, (entry->length / 1000) % 60); + tpadding_dwidth = MAX(tpadding_dwidth, strlen(length)); + } + } + + /* Reset */ + list = playlist->entries; + list = g_list_nth(list, pl->first); + + for (i = pl->first; + list && i < pl->first + pl->num_visible; + list = g_list_next(list), i++) { + entry = list->data; + + if (entry->selected && !in_selection) { + yc = ((i - pl->first) * pl->fheight); + + cairo_new_path(cr); + + cairo_move_to(cr, 0, yc + (rounding_offset * 2)); + cairo_curve_to(cr, 0, yc + rounding_offset, 0, yc + 0.5, 0 + rounding_offset, yc + 0.5); + + cairo_line_to(cr, 0 + width - (rounding_offset * 2), yc + 0.5); + cairo_curve_to(cr, 0 + width - rounding_offset, yc + 0.5, + 0 + width, yc + 0.5, 0 + width, yc + rounding_offset); + + in_selection = TRUE; + } + + if ((!entry->selected || + (i == pl->first + pl->num_visible - 1) || !g_list_next(list)) + && in_selection) { + + if (!entry->selected) + yc = (((i - 1) - pl->first) * pl->fheight); + else /* last visible item */ + yc = ((i - pl->first) * pl->fheight); + + cairo_line_to(cr, 0 + width, yc + pl->fheight - (rounding_offset * 2)); + cairo_curve_to (cr, 0 + width, yc + pl->fheight - rounding_offset, + 0 + width, yc + pl->fheight - 0.5, + 0 + width-rounding_offset, yc + pl->fheight - 0.5); + + cairo_line_to (cr, 0 + (rounding_offset * 2), yc + pl->fheight - 0.5); + cairo_curve_to (cr, 0 + rounding_offset, yc + pl->fheight - 0.5, + 0, yc + pl->fheight - 0.5, + 0, yc + pl->fheight - rounding_offset); + + cairo_close_path (cr); + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_SELECTEDBG)); + + cairo_fill(cr); + + in_selection = FALSE; + } + } + + list = playlist->entries; + list = g_list_nth(list, pl->first); + + /* now draw the text */ + for (i = pl->first; + list && i < pl->first + pl->num_visible; + list = g_list_next(list), i++) { + entry = list->data; + + /* FIXME: entry->title should NEVER be NULL, and there should + NEVER be a need to do a UTF-8 conversion. Playlist title + strings should be kept properly. */ + + if (!entry->title) { + gchar *realfn = g_filename_from_uri(entry->filename, NULL, NULL); + gchar *basename = g_path_get_basename(realfn ? realfn : entry->filename); + title = aud_filename_to_utf8(basename); + g_free(basename); g_free(realfn); + } + else + title = aud_str_to_utf8(entry->title); + + title = aud_convert_title_text(title); + + pos = aud_playlist_get_queue_position(playlist, entry); + + tail[0] = 0; + queuepos[0] = 0; + length[0] = 0; + + if (pos != -1) + g_snprintf(queuepos, sizeof(queuepos), "%d", pos + 1); + + if (entry->length != -1) + { + g_snprintf(length, sizeof(length), "%d:%-2.2d", + entry->length / 60000, (entry->length / 1000) % 60); + } + + strncat(tail, length, sizeof(tail) - 1); + tail_len = strlen(tail); + + max_time_len = MAX(max_time_len, tail_len); + + if (pos != -1 && tpadding_dwidth <= 0) + tail_width = width - (width_approx_digits * (strlen(queuepos) + 2.25)); + else if (pos != -1) + tail_width = width - (width_approx_digits * (tpadding_dwidth + strlen(queuepos) + 4)); + else if (tpadding_dwidth > 0) + tail_width = width - (width_approx_digits * (tpadding_dwidth + 2.5)); + else + tail_width = width; + + if (i == aud_playlist_get_position_nolock(playlist)) + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); + else + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMAL)); + + playlist_list_draw_string(cr, pl, playlist_list_font, + i - pl->first, tail_width, title, + i + 1); + + x = width - width_approx_digits * 2; + y = ((i - pl->first) - 1) * pl->fheight + ascent; + + frags = NULL; + frag0 = NULL; + + if ((strlen(tail) > 0) && (tail != NULL)) { + frags = g_strsplit(tail, ":", 0); + frag0 = g_strconcat(frags[0], ":", NULL); + + layout = gtk_widget_create_pango_layout(playlistwin, frags[1]); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, tail_len * 100); + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + + cairo_new_path(cr); + cairo_move_to(cr, x - (0.5 * width_approx_digits), y + abs(descent)); + pango_cairo_show_layout(cr, layout); + g_object_unref(layout); + + layout = gtk_widget_create_pango_layout(playlistwin, frag0); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, tail_len * 100); + pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); + + cairo_move_to(cr, x - (0.75 * width_approx_digits), y + abs(descent)); + pango_cairo_show_layout(cr, layout); + g_object_unref(layout); + + g_free(frag0); + g_strfreev(frags); + } + + if (pos != -1) { + if (tpadding_dwidth > 0) + queue_tailpadding = tpadding_dwidth + 1; + else + queue_tailpadding = -0.75; + + cairo_rectangle(cr, + x - + (((queue_tailpadding + + strlen(queuepos)) * + width_approx_digits) + + (width_approx_digits / 4)), + y + abs(descent), + (strlen(queuepos)) * + width_approx_digits + + (width_approx_digits / 2), + pl->fheight - 2); + + layout = + gtk_widget_create_pango_layout(playlistwin, queuepos); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); + + cairo_move_to(cr, + x - + ((queue_tailpadding + + strlen(queuepos)) * width_approx_digits) + + (width_approx_digits / 4), + y + abs(descent)); + pango_cairo_show_layout(cr, layout); + + g_object_unref(layout); + } + + cairo_stroke(cr); + + g_free(title); + } + + + /* + * Drop target hovering over the playlist, so draw some hint where the + * drop will occur. + * + * This is (currently? unfixably?) broken when dragging files from Qt/KDE apps, + * probably due to DnD signaling problems (actually i have no clue). + * + */ + + if (pl->drag_motion) { + guint pos, plength, lpadding; + + if (config.show_numbers_in_pl) { + lpadding = gint_count_digits(aud_playlist_get_length(playlist)) + 1; + lpadding = ((lpadding + 1) * width_approx_digits); + } + else { + lpadding = 3; + }; + + /* We already hold the mutex and have the playlist locked, so call + the non-locking function. */ + plength = aud_playlist_get_length(playlist); + + x = pl->drag_motion_x; + y = pl->drag_motion_y; + + if ((x > pl->x) && !(x > priv->width)) { + + if ((y > pl->y) + && !(y > (priv->height + pl->y))) { + + pos = (y / pl->fheight) + + pl->first; + + if (pos > (plength)) { + pos = plength; + } + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); + + cairo_new_path(cr); + + cairo_move_to(cr, 0, ((pos - pl->first) * pl->fheight)); + cairo_rel_line_to(cr, priv->width - 1, 0); + + cairo_set_line_width(cr, 1); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_stroke(cr); + } + + } + + /* When dropping on the borders of the playlist, outside the text area, + * files get appended at the end of the list. Show that too. + */ + + if ((y < pl->y) || (y > priv->height + pl->y)) { + if ((y >= 0) || (y <= (priv->height + pl->y))) { + pos = plength; + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); + + cairo_new_path(cr); + + cairo_move_to(cr, 0, ((pos - pl->first) * pl->fheight)); + cairo_rel_line_to(cr, priv->width - 1, 0); + + cairo_set_line_width(cr, 1); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_stroke(cr); + } + } + } + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMAL)); + cairo_set_line_width(cr, 1); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + + if (config.show_numbers_in_pl) + { + padding_plength = aud_playlist_get_length(playlist); + + if (padding_plength == 0) { + padding_dwidth = 0; + } + else { + padding_dwidth = gint_count_digits(aud_playlist_get_length(playlist)); + } + + padding = + (padding_dwidth * + width_approx_digits) + width_approx_digits; + + + /* For italic or oblique fonts we add another half of the + * approximate width */ + if (has_slant) + padding += width_approx_digits_half; + + if (config.show_separator_in_pl) { + cairo_new_path(cr); + + cairo_move_to(cr, padding, 0); + cairo_rel_line_to(cr, 0, priv->height - 1); + + cairo_stroke(cr); + } + } + + if (tpadding_dwidth != 0) + { + tpadding = (tpadding_dwidth * width_approx_digits) + (width_approx_digits * 1.5); + + if (has_slant) + tpadding += width_approx_digits_half; + + if (config.show_separator_in_pl) { + cairo_new_path(cr); + + cairo_move_to(cr, priv->width - tpadding, 0); + cairo_rel_line_to(cr, 0, priv->height - 1); + + cairo_stroke(cr); + } + } + + PLAYLIST_UNLOCK(playlist); + + cairo_destroy(cr); + + return FALSE; +} + +gint ui_skinned_playlist_get_position(GtkWidget *widget, gint x, gint y) { + gint iy, length; + gint ret; + Playlist *playlist = aud_playlist_get_active(); + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); + + if (!pl->fheight) + return -1; + + if ((length = aud_playlist_get_length(playlist)) == 0) + return -1; + iy = y; + + ret = (iy / pl->fheight) + pl->first; + + if (ret > length - 1) + ret = -1; + + return ret; +} + +static gboolean ui_skinned_playlist_button_press(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + gint nr; + Playlist *playlist = aud_playlist_get_active(); + + nr = ui_skinned_playlist_get_position(widget, event->x, event->y); + if (nr == -1) + return FALSE; + + if (event->button == 3) { + ui_manager_popup_menu_show(GTK_MENU(playlistwin_popup_menu), + event->x_root, event->y_root + 5, + event->button, event->time); + GList* selection = aud_playlist_get_selected(playlist); + if (g_list_find(selection, GINT_TO_POINTER(nr)) == NULL) { + aud_playlist_select_all(playlist, FALSE); + aud_playlist_select_range(playlist, nr, nr, TRUE); + } + } else if (event->button == 1) { + if (!(event->state & GDK_CONTROL_MASK)) + aud_playlist_select_all(playlist, FALSE); + + if ((event->state & GDK_MOD1_MASK)) + aud_playlist_queue_position(playlist, nr); + + if (event->state & GDK_SHIFT_MASK && pl->prev_selected != -1) { + aud_playlist_select_range(playlist, pl->prev_selected, nr, TRUE); + pl->prev_min = pl->prev_selected; + pl->prev_max = nr; + priv->drag_pos = nr - pl->first; + } + else { + if (aud_playlist_select_invert(playlist, nr)) { + if (event->state & GDK_CONTROL_MASK) { + if (pl->prev_min == -1) { + pl->prev_min = pl->prev_selected; + pl->prev_max = pl->prev_selected; + } + if (nr < pl->prev_min) + pl->prev_min = nr; + else if (nr > pl->prev_max) + pl->prev_max = nr; + } + else + pl->prev_min = -1; + pl->prev_selected = nr; + priv->drag_pos = nr - pl->first; + } + } + if (event->type == GDK_2BUTTON_PRESS) { + /* + * Ungrab the pointer to prevent us from + * hanging on to it during the sometimes slow + * audacious_drct_initiate(). + */ + gdk_pointer_ungrab(GDK_CURRENT_TIME); + aud_playlist_set_position(playlist, nr); + if (!audacious_drct_get_playing()) + audacious_drct_initiate(); + } + + priv->dragging = TRUE; + } + playlistwin_update_list(playlist); + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + + return TRUE; +} + +static gboolean ui_skinned_playlist_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + priv->dragging = FALSE; + priv->auto_drag_down = FALSE; + priv->auto_drag_up = FALSE; + gtk_widget_queue_draw(widget); + + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + return TRUE; +} + +static gboolean ui_skinned_playlist_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + gint nr, y, off, i; + if (priv->dragging) { + y = event->y; + nr = (y / pl->fheight); + if (nr < 0) { + nr = 0; + if (!priv->auto_drag_up) { + priv->auto_drag_up = TRUE; + priv->auto_drag_up_tag = + g_timeout_add(100, ui_skinned_playlist_auto_drag_up_func, pl); + } + } + else if (priv->auto_drag_up) + priv->auto_drag_up = FALSE; + + if (nr >= pl->num_visible) { + nr = pl->num_visible - 1; + if (!priv->auto_drag_down) { + priv->auto_drag_down = TRUE; + priv->auto_drag_down_tag = + g_timeout_add(100, ui_skinned_playlist_auto_drag_down_func, pl); + } + } + else if (priv->auto_drag_down) + priv->auto_drag_down = FALSE; + + off = nr - priv->drag_pos; + if (off) { + for (i = 0; i < abs(off); i++) { + if (off < 0) + ui_skinned_playlist_move_up(pl); + else + ui_skinned_playlist_move_down(pl); + + } + playlistwin_update_list(aud_playlist_get_active()); + } + priv->drag_pos = nr; + } else if (aud_cfg->show_filepopup_for_tuple) { + gint pos = ui_skinned_playlist_get_position(widget, event->x, event->y); + gint cur_pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_position")); + if (pos != cur_pos) { + g_object_set_data(G_OBJECT(widget), "popup_position", GINT_TO_POINTER(pos)); + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + if (pos != -1) + ui_skinned_playlist_popup_timer_start(widget); + } + } + + return TRUE; +} + +static gboolean ui_skinned_playlist_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + + return FALSE; +} + +static void ui_skinned_playlist_redraw(UiSkinnedPlaylist *playlist) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); + + if (priv->resize_height || priv->resize_width) + gtk_widget_set_size_request(GTK_WIDGET(playlist), priv->width+priv->resize_width, priv->height+priv->resize_height); + + gtk_widget_queue_draw(GTK_WIDGET(playlist)); +} + +void ui_skinned_playlist_set_font(const gchar * font) { + /* Welcome to bad hack central 2k3 */ + gchar *font_lower; + gint width_temp; + gint width_temp_0; + + playlist_list_font = pango_font_description_from_string(font); + + text_get_extents(font, + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ", + &width_approx_letters, NULL, &ascent, &descent); + + width_approx_letters = (width_approx_letters / 53); + + /* Experimental: We don't weigh the 1 into total because it's width is almost always + * very different from the rest + */ + text_get_extents(font, "023456789", &width_approx_digits, NULL, NULL, + NULL); + width_approx_digits = (width_approx_digits / 9); + + /* Precache some often used calculations */ + width_approx_digits_half = width_approx_digits / 2; + + /* FIXME: We assume that any other number is broader than the "1" */ + text_get_extents(font, "1", &width_temp, NULL, NULL, NULL); + text_get_extents(font, "2", &width_temp_0, NULL, NULL, NULL); + + if (abs(width_temp_0 - width_temp) < 2) { + width_delta_digit_one = 0; + } + else { + width_delta_digit_one = ((width_temp_0 - width_temp) / 2) + 2; + } + + text_get_extents(font, ":", &width_colon, NULL, NULL, NULL); + width_colon_third = width_colon / 4; + + font_lower = g_utf8_strdown(font, strlen(font)); + /* This doesn't take any i18n into account, but i think there is none with TTF fonts + * FIXME: This can probably be retrieved trough Pango too + */ + has_slant = g_strstr_len(font_lower, strlen(font_lower), "oblique") + || g_strstr_len(font_lower, strlen(font_lower), "italic"); + + g_free(font_lower); +} + +void ui_skinned_playlist_resize_relative(GtkWidget *widget, gint w, gint h) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + priv->resize_width += w; + priv->resize_height += h; +} + +static gboolean ui_skinned_playlist_popup_show(gpointer data) { +#if 0 + GtkWidget *widget = data; + gint pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_position")); + + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_active")) == 1 && pos != -1) { + Tuple *tuple; + Playlist *pl_active = aud_playlist_get_active(); + GtkWidget *popup = g_object_get_data(G_OBJECT(widget), "popup"); + + tuple = playlist_get_tuple(pl_active, pos); + if ((tuple == NULL) || (tuple_get_int(tuple, FIELD_LENGTH, NULL) < 1)) { + gchar *title = aud_playlist_get_songtitle(pl_active, pos); + fileinfopopup_show_from_title(popup, title); + g_free(title); + } else { + fileinfopopup_show_from_tuple(popup , tuple); + } + g_object_set_data(G_OBJECT(widget), "popup_active" , GINT_TO_POINTER(1)); + } + + ui_skinned_playlist_popup_timer_stop(widget); + return FALSE; +#endif +} + +static void ui_skinned_playlist_popup_hide(GtkWidget *widget) { +#if 0 + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_active")) == 1) { + GtkWidget *popup = g_object_get_data(G_OBJECT(widget), "popup"); + g_object_set_data(G_OBJECT(widget), "popup_active", GINT_TO_POINTER(0)); + fileinfopopup_hide(popup, NULL); + } +#endif +} + +static void ui_skinned_playlist_popup_timer_start(GtkWidget *widget) { + gint timer_id = g_timeout_add(aud_cfg->filepopup_delay*100, ui_skinned_playlist_popup_show, widget); + g_object_set_data(G_OBJECT(widget), "timer_id", GINT_TO_POINTER(timer_id)); + g_object_set_data(G_OBJECT(widget), "timer_active", GINT_TO_POINTER(1)); +} + +static void ui_skinned_playlist_popup_timer_stop(GtkWidget *widget) { + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_active")) == 1) + g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_id"))); + + g_object_set_data(G_OBJECT(widget), "timer_id", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(widget), "timer_active", GINT_TO_POINTER(0)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_playlist.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,77 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_PLAYLIST_H +#define AUDACIOUS_UI_SKINNED_PLAYLIST_H + +#include <gtk/gtk.h> + +#include <cairo.h> +#include <pango/pangocairo.h> + +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_PLAYLIST(obj) GTK_CHECK_CAST (obj, ui_skinned_playlist_get_type (), UiSkinnedPlaylist) +#define UI_SKINNED_PLAYLIST_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playlist_get_type (), UiSkinnedPlaylistClass) +#define UI_SKINNED_IS_PLAYLIST(obj) GTK_CHECK_TYPE (obj, ui_skinned_playlist_get_type ()) + +typedef struct _UiSkinnedPlaylist UiSkinnedPlaylist; +typedef struct _UiSkinnedPlaylistClass UiSkinnedPlaylistClass; + +struct _UiSkinnedPlaylist { + GtkWidget widget; + gboolean pressed; + gint x, y; + gint first; + gint num_visible; + gint prev_selected, prev_min, prev_max; + gboolean drag_motion; + gint drag_motion_x, drag_motion_y; + gint fheight; +}; + +struct _UiSkinnedPlaylistClass { + GtkWidgetClass parent_class; + void (* redraw) (UiSkinnedPlaylist *playlist); +}; + +GtkWidget* ui_skinned_playlist_new(GtkWidget *fixed, gint x, gint y, gint w, gint h); +GtkType ui_skinned_playlist_get_type(void); +void ui_skinned_playlist_resize_relative(GtkWidget *widget, gint w, gint h); +void ui_skinned_playlist_set_font(const gchar * font); +void ui_skinned_playlist_move_up(UiSkinnedPlaylist *pl); +void ui_skinned_playlist_move_down(UiSkinnedPlaylist *pl); +gint ui_skinned_playlist_get_position(GtkWidget *widget, gint x, gint y); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_PLAYLIST_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_playlist_slider.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,337 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skin.h" +#include "ui_skinned_playlist_slider.h" +#include "ui_playlist.h" + +#define UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_playlist_slider_get_type(), UiSkinnedPlaylistSliderPrivate)) +typedef struct _UiSkinnedPlaylistSliderPrivate UiSkinnedPlaylistSliderPrivate; + +enum { + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedPlaylistSliderPrivate { + SkinPixmapId skin_index; + gint width, height; + + gint resize_height; + gint move_x; + gint prev_y; + gint drag_y; +}; + +static void ui_skinned_playlist_slider_class_init (UiSkinnedPlaylistSliderClass *klass); +static void ui_skinned_playlist_slider_init (UiSkinnedPlaylistSlider *playlist_slider); +static void ui_skinned_playlist_slider_destroy (GtkObject *object); +static void ui_skinned_playlist_slider_realize (GtkWidget *widget); +static void ui_skinned_playlist_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_playlist_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_playlist_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_playlist_slider_set_position (GtkWidget *widget, gint y); +static gboolean ui_skinned_playlist_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_playlist_slider_redraw (UiSkinnedPlaylistSlider *playlist_slider); + +static GtkWidgetClass *parent_class = NULL; +static guint playlist_slider_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_playlist_slider_get_type() { + static GType playlist_slider_type = 0; + if (!playlist_slider_type) { + static const GTypeInfo playlist_slider_info = { + sizeof (UiSkinnedPlaylistSliderClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_playlist_slider_class_init, + NULL, + NULL, + sizeof (UiSkinnedPlaylistSlider), + 0, + (GInstanceInitFunc) ui_skinned_playlist_slider_init, + }; + playlist_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaylistSlider", &playlist_slider_info, 0); + } + + return playlist_slider_type; +} + +static void ui_skinned_playlist_slider_class_init(UiSkinnedPlaylistSliderClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_playlist_slider_destroy; + + widget_class->realize = ui_skinned_playlist_slider_realize; + widget_class->expose_event = ui_skinned_playlist_slider_expose; + widget_class->size_request = ui_skinned_playlist_slider_size_request; + widget_class->size_allocate = ui_skinned_playlist_slider_size_allocate; + widget_class->button_press_event = ui_skinned_playlist_slider_button_press; + widget_class->button_release_event = ui_skinned_playlist_slider_button_release; + widget_class->motion_notify_event = ui_skinned_playlist_slider_motion_notify; + + klass->redraw = ui_skinned_playlist_slider_redraw; + + playlist_slider_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedPlaylistSliderClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedPlaylistSliderPrivate)); +} + +static void ui_skinned_playlist_slider_init(UiSkinnedPlaylistSlider *playlist_slider) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); + playlist_slider->pressed = FALSE; + priv->resize_height = 0; + priv->move_x = 0; + priv->drag_y = 0; + priv->prev_y = 0; +} + +GtkWidget* ui_skinned_playlist_slider_new(GtkWidget *fixed, gint x, gint y, gint h) { + + UiSkinnedPlaylistSlider *hs = g_object_new (ui_skinned_playlist_slider_get_type (), NULL); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(hs); + + hs->x = x; + hs->y = y; + priv->width = 8; + priv->height = h; + priv->skin_index = SKIN_PLEDIT; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); + + return GTK_WIDGET(hs); +} + +static void ui_skinned_playlist_slider_destroy(GtkObject *object) { + UiSkinnedPlaylistSlider *playlist_slider; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER (object)); + + playlist_slider = UI_SKINNED_PLAYLIST_SLIDER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_playlist_slider_realize(GtkWidget *widget) { + UiSkinnedPlaylistSlider *playlist_slider; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + playlist_slider = UI_SKINNED_PLAYLIST_SLIDER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_playlist_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + requisition->width = priv->width; + requisition->height = priv->height; +} + +static void ui_skinned_playlist_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedPlaylistSlider *playlist_slider = UI_SKINNED_PLAYLIST_SLIDER (widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + if (playlist_slider->x + priv->move_x == widget->allocation.x) + priv->move_x = 0; + playlist_slider->x = widget->allocation.x; + playlist_slider->y = widget->allocation.y; + + if (priv->height != widget->allocation.height) { + priv->height = priv->height + priv->resize_height; + priv->resize_height = 0; + gtk_widget_queue_draw(widget); + } +} + +static gboolean ui_skinned_playlist_slider_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER (widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(ps); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); + + gint num_visible; + num_visible = playlistwin_list_get_visible_count(); + + + Playlist *playlist = aud_playlist_get_active(); + + gint y; + if (aud_playlist_get_length(playlist) > num_visible) + y = (playlistwin_list_get_first() * (priv->height - 19)) / + (aud_playlist_get_length(playlist) - num_visible); + else + y = 0; + + if (y < 0) y=0; + if (y > priv->height - 19) y = priv->height - 19; + + priv->prev_y = y; + + /* FIXME: uses aud_active_skin->pixmaps directly and may need calibration */ + /* drawing background */ + gint c; + for (c = 0; c < priv->height / 29; c++) { + gdk_pixbuf_copy_area(aud_active_skin->pixmaps[SKIN_PLEDIT].pixbuf, + 36, 42, priv->width, 29, obj, 0, c*29); + } + + /* drawing knob */ + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, ps->pressed ? 61 : 52, 53, 0, y, priv->width, 18); + + ui_skinned_widget_draw(widget, obj, priv->width, priv->height, FALSE); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_playlist_slider_set_position(GtkWidget *widget, gint y) { + gint pos; + Playlist *playlist = aud_playlist_get_active(); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + y = CLAMP(y, 0, priv->height - 19); + + pos = (y * (aud_playlist_get_length(playlist) - playlistwin_list_get_visible_count())) / (priv->height - 19); + playlistwin_set_toprow(pos); + + gtk_widget_queue_draw(widget); +} + +static gboolean ui_skinned_playlist_slider_button_press(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER (widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + if (event->button != 1 && event->button != 2) + return TRUE; + + gint y = event->y; + if (event->type == GDK_BUTTON_PRESS) { + ps->pressed = TRUE; + if ((y >= priv->prev_y && y < priv->prev_y + 18)) { + priv->drag_y = y - priv->prev_y; + } else if (event->button == 2) { + ui_skinned_playlist_slider_set_position(widget, y); + priv->drag_y = 0; + } else { + gint n = playlistwin_list_get_visible_count() / 2; + if (y < priv->prev_y) + n *= -1; + playlistwin_scroll(n); + } + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_playlist_slider_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER(widget); + + if (event->button == 1 || event->button == 2) { + ps->pressed = FALSE; + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_playlist_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER(widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + if (ps->pressed) { + gint y = event->y - priv->drag_y; + ui_skinned_playlist_slider_set_position(widget, y); + } + return TRUE; +} + +static void ui_skinned_playlist_slider_redraw(UiSkinnedPlaylistSlider *playlist_slider) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); + + if (priv->resize_height) + gtk_widget_set_size_request(GTK_WIDGET(playlist_slider), priv->width, priv->height+priv->resize_height); + if (priv->move_x) + gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(playlist_slider))), GTK_WIDGET(playlist_slider), + playlist_slider->x+priv->move_x, playlist_slider->y); + + gtk_widget_queue_draw(GTK_WIDGET(playlist_slider)); +} + +void ui_skinned_playlist_slider_move_relative(GtkWidget *widget, gint x) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + priv->move_x += x; +} + +void ui_skinned_playlist_slider_resize_relative(GtkWidget *widget, gint h) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + priv->resize_height += h; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_playlist_slider.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H +#define AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H + +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_PLAYLIST_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_playlist_slider_get_type (), UiSkinnedPlaylistSlider) +#define UI_SKINNED_PLAYLIST_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playlist_slider_get_type (), UiSkinnedPlaylistSliderClass) +#define UI_SKINNED_IS_PLAYLIST_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_playlist_slider_get_type ()) + +typedef struct _UiSkinnedPlaylistSlider UiSkinnedPlaylistSlider; +typedef struct _UiSkinnedPlaylistSliderClass UiSkinnedPlaylistSliderClass; + +struct _UiSkinnedPlaylistSlider { + GtkWidget widget; + gboolean pressed; + gint x, y; +}; + +struct _UiSkinnedPlaylistSliderClass { + GtkWidgetClass parent_class; + void (* redraw) (UiSkinnedPlaylistSlider *playlist_slider); +}; + +GtkWidget* ui_skinned_playlist_slider_new(GtkWidget *fixed, gint x, gint y, gint h); +GtkType ui_skinned_playlist_slider_get_type(void); +void ui_skinned_playlist_slider_move_relative(GtkWidget *widget, gint x); +void ui_skinned_playlist_slider_resize_relative(GtkWidget *widget, gint h); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_playstatus.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,246 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skin.h" +#include "ui_skinned_playstatus.h" +#include "skins_cfg.h" + +#define UI_TYPE_SKINNED_PLAYSTATUS (ui_skinned_playstatus_get_type()) + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_playstatus_class_init (UiSkinnedPlaystatusClass *klass); +static void ui_skinned_playstatus_init (UiSkinnedPlaystatus *playstatus); +static void ui_skinned_playstatus_destroy (GtkObject *object); +static void ui_skinned_playstatus_realize (GtkWidget *widget); +static void ui_skinned_playstatus_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_playstatus_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_playstatus_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_playstatus_toggle_scaled (UiSkinnedPlaystatus *playstatus); + +static GtkWidgetClass *parent_class = NULL; +static guint playstatus_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_playstatus_get_type() { + static GType playstatus_type = 0; + if (!playstatus_type) { + static const GTypeInfo playstatus_info = { + sizeof (UiSkinnedPlaystatusClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_playstatus_class_init, + NULL, + NULL, + sizeof (UiSkinnedPlaystatus), + 0, + (GInstanceInitFunc) ui_skinned_playstatus_init, + }; + playstatus_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaystatus", &playstatus_info, 0); + } + + return playstatus_type; +} + +static void ui_skinned_playstatus_class_init(UiSkinnedPlaystatusClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_playstatus_destroy; + + widget_class->realize = ui_skinned_playstatus_realize; + widget_class->expose_event = ui_skinned_playstatus_expose; + widget_class->size_request = ui_skinned_playstatus_size_request; + widget_class->size_allocate = ui_skinned_playstatus_size_allocate; + + klass->scaled = ui_skinned_playstatus_toggle_scaled; + + playstatus_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedPlaystatusClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_playstatus_init(UiSkinnedPlaystatus *playstatus) { + playstatus->width = 11; + playstatus->height = 9; +} + +GtkWidget* ui_skinned_playstatus_new(GtkWidget *fixed, gint x, gint y) { + UiSkinnedPlaystatus *playstatus = g_object_new (ui_skinned_playstatus_get_type (), NULL); + + playstatus->x = x; + playstatus->y = y; + + playstatus->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(playstatus), playstatus->x, playstatus->y); + + return GTK_WIDGET(playstatus); +} + +static void ui_skinned_playstatus_destroy(GtkObject *object) { + UiSkinnedPlaystatus *playstatus; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (object)); + + playstatus = UI_SKINNED_PLAYSTATUS (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_playstatus_realize(GtkWidget *widget) { + UiSkinnedPlaystatus *playstatus; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + playstatus = UI_SKINNED_PLAYSTATUS(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_playstatus_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS(widget); + + requisition->width = playstatus->width*(playstatus->scaled ? config.scale_factor : 1); + requisition->height = playstatus->height*(playstatus->scaled ? config.scale_factor : 1); +} + +static void ui_skinned_playstatus_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (playstatus->scaled ? config.scale_factor : 1); + widget->allocation.y *= (playstatus->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + playstatus->x = widget->allocation.x/(playstatus->scaled ? config.scale_factor : 1); + playstatus->y = widget->allocation.y/(playstatus->scaled ? config.scale_factor : 1); +} + +static gboolean ui_skinned_playstatus_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + g_return_val_if_fail (playstatus->width > 0 && playstatus->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, playstatus->width, playstatus->height); + + if (playstatus->status == STATUS_STOP && playstatus->buffering == TRUE) + playstatus->buffering = FALSE; + if (playstatus->status == STATUS_PLAY && playstatus->buffering == TRUE) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 39, 0, 0, 0, 3, playstatus->height); + else if (playstatus->status == STATUS_PLAY) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 36, 0, 0, 0, 3, playstatus->height); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 27, 0, 0, 0, 2, playstatus->height); + switch (playstatus->status) { + case STATUS_STOP: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 18, 0, 2, 0, 9, playstatus->height); + break; + case STATUS_PAUSE: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 9, 0, 2, 0, 9, playstatus->height); + break; + case STATUS_PLAY: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 1, 0, 3, 0, 8, playstatus->height); + break; + } + + ui_skinned_widget_draw(widget, obj, playstatus->width, playstatus->height, playstatus->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_playstatus_toggle_scaled(UiSkinnedPlaystatus *playstatus) { + GtkWidget *widget = GTK_WIDGET (playstatus); + + playstatus->scaled = !playstatus->scaled; + gtk_widget_set_size_request(widget, playstatus->width*(playstatus->scaled ? config.scale_factor : 1), playstatus->height*(playstatus->scaled ? config.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(playstatus)); +} + +void ui_skinned_playstatus_set_status(GtkWidget *widget, PStatus status) { + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + playstatus->status = status; + gtk_widget_queue_draw(widget); +} + +void ui_skinned_playstatus_set_buffering(GtkWidget *widget, gboolean status) { + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + playstatus->buffering = status; + gtk_widget_queue_draw(widget); +} + +void ui_skinned_playstatus_set_size(GtkWidget *widget, gint width, gint height) { + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + playstatus->width = width; + playstatus->height = height; + + gtk_widget_set_size_request(widget, width*(playstatus->scaled ? config.scale_factor : 1), height*(playstatus->scaled ? config.scale_factor : 1)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_playstatus.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,71 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_PLAYSTATUS_H +#define AUDACIOUS_UI_SKINNED_PLAYSTATUS_H + +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_PLAYSTATUS(obj) GTK_CHECK_CAST (obj, ui_skinned_playstatus_get_type (), UiSkinnedPlaystatus) +#define UI_SKINNED_PLAYSTATUS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playstatus_get_type (), UiSkinnedPlaystatusClass) +#define UI_SKINNED_IS_PLAYSTATUS(obj) GTK_CHECK_TYPE (obj, ui_skinned_playstatus_get_type ()) + +typedef struct _UiSkinnedPlaystatus UiSkinnedPlaystatus; +typedef struct _UiSkinnedPlaystatusClass UiSkinnedPlaystatusClass; + +typedef enum { + STATUS_STOP, STATUS_PAUSE, STATUS_PLAY +} PStatus; + +struct _UiSkinnedPlaystatus { + GtkWidget widget; + + gint x, y, width, height; + gboolean scaled; + PStatus status; + gboolean buffering; +}; + +struct _UiSkinnedPlaystatusClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedPlaystatus *menurow); +}; + +GtkWidget* ui_skinned_playstatus_new (GtkWidget *fixed, gint x, gint y); +GtkType ui_skinned_playstatus_get_type(void); +void ui_skinned_playstatus_set_status(GtkWidget *widget, PStatus status); +void ui_skinned_playstatus_set_buffering(GtkWidget *widget, gboolean status); +void ui_skinned_playstatus_set_size(GtkWidget *widget, gint width, gint height); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_PLAYSTATUS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_textbox.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,870 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz MoÅ„ + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skinned_textbox.h" +#include "skins_cfg.h" +#include "plugin.h" +#include <string.h> + +#include "util.h" + +#define UI_SKINNED_TEXTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_textbox_get_type(), UiSkinnedTextboxPrivate)) +typedef struct _UiSkinnedTextboxPrivate UiSkinnedTextboxPrivate; + +#define TEXTBOX_SCROLL_SMOOTH_TIMEOUT 30 +#define TEXTBOX_SCROLL_WAIT 80 + +enum { + CLICKED, + DOUBLE_CLICKED, + RIGHT_CLICKED, + DOUBLED, + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedTextboxPrivate { + SkinPixmapId skin_index; + gboolean scaled; + gboolean scroll_back; + gint nominal_y, nominal_height; + gint scroll_timeout; + gint font_ascent, font_descent; + PangoFontDescription *font; + gchar *fontname; + gchar *pixbuf_text; + gint skin_id; + gint drag_x, drag_off, offset; + gboolean is_scrollable, is_dragging; + gint pixbuf_width; + GdkPixbuf *pixbuf; + gboolean scroll_allowed, scroll_enabled; + gint scroll_dummy; + gint move_x, move_y; +}; + +static void ui_skinned_textbox_class_init (UiSkinnedTextboxClass *klass); +static void ui_skinned_textbox_init (UiSkinnedTextbox *textbox); +static void ui_skinned_textbox_destroy (GtkObject *object); +static void ui_skinned_textbox_realize (GtkWidget *widget); +static void ui_skinned_textbox_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_textbox_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_textbox_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_textbox_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_textbox_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_textbox_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_textbox_toggle_scaled (UiSkinnedTextbox *textbox); +static void ui_skinned_textbox_redraw (UiSkinnedTextbox *textbox); +static gboolean ui_skinned_textbox_should_scroll (UiSkinnedTextbox *textbox); +static void textbox_generate_xfont_pixmap (UiSkinnedTextbox *textbox, const gchar *pixmaptext); +static gboolean textbox_scroll (gpointer data); +static void textbox_generate_pixmap (UiSkinnedTextbox *textbox); +static void textbox_handle_special_char (gchar *c, gint * x, gint * y); + +static GtkWidgetClass *parent_class = NULL; +static guint textbox_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_textbox_get_type() { + static GType textbox_type = 0; + if (!textbox_type) { + static const GTypeInfo textbox_info = { + sizeof (UiSkinnedTextboxClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_textbox_class_init, + NULL, + NULL, + sizeof (UiSkinnedTextbox), + 0, + (GInstanceInitFunc) ui_skinned_textbox_init, + }; + textbox_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedTextbox", &textbox_info, 0); + } + + return textbox_type; +} + +static void ui_skinned_textbox_class_init(UiSkinnedTextboxClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_textbox_destroy; + + widget_class->realize = ui_skinned_textbox_realize; + widget_class->expose_event = ui_skinned_textbox_expose; + widget_class->size_request = ui_skinned_textbox_size_request; + widget_class->size_allocate = ui_skinned_textbox_size_allocate; + widget_class->button_press_event = ui_skinned_textbox_button_press; + widget_class->button_release_event = ui_skinned_textbox_button_release; + widget_class->motion_notify_event = ui_skinned_textbox_motion_notify; + + klass->clicked = NULL; + klass->double_clicked = NULL; + klass->right_clicked = NULL; + klass->scaled = ui_skinned_textbox_toggle_scaled; + klass->redraw = ui_skinned_textbox_redraw; + + textbox_signals[CLICKED] = + g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, clicked), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + textbox_signals[DOUBLE_CLICKED] = + g_signal_new ("double-clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, double_clicked), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + textbox_signals[RIGHT_CLICKED] = + g_signal_new ("right-clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, right_clicked), NULL, NULL, + gtk_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + + textbox_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + textbox_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedTextboxPrivate)); +} + +static void ui_skinned_textbox_init(UiSkinnedTextbox *textbox) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + priv->move_x = 0; + priv->move_y = 0; +} + +GtkWidget* ui_skinned_textbox_new(GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si) { + UiSkinnedTextbox *textbox = g_object_new (ui_skinned_textbox_get_type (), NULL); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + textbox->height = aud_active_skin->properties.textbox_bitmap_font_height; + textbox->x = x; + textbox->y = y; + textbox->text = g_strdup(""); + textbox->width = w; + priv->scroll_allowed = allow_scroll; + priv->scroll_enabled = TRUE; + priv->skin_index = si; + priv->nominal_y = y; + priv->nominal_height = textbox->height; + priv->scroll_timeout = 0; + priv->scroll_dummy = 0; + + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(textbox), textbox->x, textbox->y); + + return GTK_WIDGET(textbox); +} + +static void ui_skinned_textbox_destroy(GtkObject *object) { + UiSkinnedTextbox *textbox; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_TEXTBOX (object)); + + textbox = UI_SKINNED_TEXTBOX (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_textbox_realize(GtkWidget *widget) { + UiSkinnedTextbox *textbox; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_TEXTBOX(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + textbox = UI_SKINNED_TEXTBOX(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_textbox_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + requisition->width = textbox->width*(priv->scaled ? config.scale_factor : 1); + requisition->height = textbox->height*(priv->scaled ? config.scale_factor : 1 ); +} + +static void ui_skinned_textbox_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + widget->allocation = *allocation; + widget->allocation.x *= (priv->scaled ? config.scale_factor : 1); + widget->allocation.y *= (priv->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + if (textbox->x + priv->move_x - widget->allocation.x/(priv->scaled ? config.scale_factor : 1) <3); + priv->move_x = 0; + if (textbox->y + priv->move_y - widget->allocation.y/(priv->scaled ? config.scale_factor : 1) <3); + priv->move_y = 0; + textbox->x = widget->allocation.x/(priv->scaled ? config.scale_factor : 1); + textbox->y = widget->allocation.y/(priv->scaled ? config.scale_factor : 1); + + if (textbox->width - (guint) (widget->allocation.width / (priv->scaled ? config.scale_factor : 1)) > 2) { + textbox->width = (guint) (widget->allocation.width / (priv->scaled ? config.scale_factor : 1)); + if (priv->pixbuf_text) g_free(priv->pixbuf_text); + priv->pixbuf_text = NULL; + priv->offset = 0; + gtk_widget_set_size_request(widget, textbox->width, textbox->height); + gtk_widget_queue_draw(GTK_WIDGET(textbox)); + } +} + +static gboolean ui_skinned_textbox_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + g_return_val_if_fail (textbox->width > 0 && textbox->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + gint cw; + + if (textbox->text && (!priv->pixbuf_text || strcmp(textbox->text, priv->pixbuf_text))) + textbox_generate_pixmap(textbox); + + if (priv->pixbuf) { + if (skin_get_id() != priv->skin_id) { + priv->skin_id = skin_get_id(); + textbox_generate_pixmap(textbox); + } + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, textbox->width, textbox->height); + + if (config.twoway_scroll) { // twoway scroll + cw = priv->pixbuf_width - priv->offset; + if (cw > textbox->width) + cw = textbox->width; + gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw, textbox->height, obj, 0, 0); + if (cw < textbox->width) + gdk_pixbuf_copy_area(priv->pixbuf, 0, 0, textbox->width - cw, textbox->height, + obj, textbox->width - cw, textbox->height); + } else { // oneway scroll + int cw1, cw2; + + if (priv->offset >= priv->pixbuf_width) + priv->offset = 0; + + if (priv->pixbuf_width - priv->offset > textbox->width) { // case1 + cw1 = textbox->width; + gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw1, textbox->height, + obj, 0, 0); + } else { // case 2 + cw1 = priv->pixbuf_width - priv->offset; + gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw1, textbox->height, obj, 0, 0); + cw2 = textbox->width - cw1; + gdk_pixbuf_copy_area(priv->pixbuf, 0, 0, cw2, textbox->height, obj, cw1, 0); + } + } + + ui_skinned_widget_draw(widget, obj, textbox->width, textbox->height, priv->scaled); + + g_object_unref(obj); + } + + return FALSE; +} + +static gboolean ui_skinned_textbox_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (event->type == GDK_BUTTON_PRESS) { + textbox = UI_SKINNED_TEXTBOX(widget); + if (event->button == 3 && !g_signal_has_handler_pending(widget, textbox_signals[RIGHT_CLICKED], 0, TRUE)) + return FALSE; + else if (event->button == 1) { + if (priv->scroll_allowed) { + if ((priv->pixbuf_width > textbox->width) && priv->is_scrollable) { + priv->is_dragging = TRUE; + priv->drag_off = priv->offset; + priv->drag_x = event->x; + } + } else + g_signal_emit(widget, textbox_signals[CLICKED], 0); + + } else if (event->button == 3) { + g_signal_emit(widget, textbox_signals[RIGHT_CLICKED], 0, event); + } else + priv->is_dragging = FALSE; + } else if (event->type == GDK_2BUTTON_PRESS) { + if (event->button == 1) { + if (g_signal_has_handler_pending(widget, textbox_signals[DOUBLE_CLICKED], 0, TRUE)) + g_signal_emit(widget, textbox_signals[DOUBLE_CLICKED], 0); + else + return FALSE; + } + } + + return TRUE; +} + +static gboolean ui_skinned_textbox_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); + + if (event->button == 1) { + priv->is_dragging = FALSE; + } + + return TRUE; +} + +static gboolean ui_skinned_textbox_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); + + if (priv->is_dragging) { + if (priv->scroll_allowed && + priv->pixbuf_width > textbox->width) { + priv->offset = priv->drag_off - (event->x - priv->drag_x); + + while (priv->offset < 0) + priv->offset = 0; + + while (priv->offset > (priv->pixbuf_width - textbox->width)) + priv->offset = (priv->pixbuf_width - textbox->width); + + gtk_widget_queue_draw(widget); + } + } + + return TRUE; +} + +static void ui_skinned_textbox_toggle_scaled(UiSkinnedTextbox *textbox) { + GtkWidget *widget = GTK_WIDGET (textbox); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, textbox->width*(priv->scaled ? config.scale_factor : 1 ), + textbox->height*(priv->scaled ? config.scale_factor : 1 )); + + gtk_widget_queue_draw(GTK_WIDGET(textbox)); +} + +static void ui_skinned_textbox_redraw(UiSkinnedTextbox *textbox) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (priv->move_x || priv->move_y) + gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(textbox))), GTK_WIDGET(textbox), + textbox->x+priv->move_x, textbox->y+priv->move_y); + + gtk_widget_queue_draw(GTK_WIDGET(textbox)); +} + +static gboolean ui_skinned_textbox_should_scroll(UiSkinnedTextbox *textbox) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (!priv->scroll_allowed) + return FALSE; + + if (priv->font) { + gint width; + text_get_extents(priv->fontname, textbox->text, &width, NULL, NULL, NULL); + + if (width <= textbox->width) + return FALSE; + else + return TRUE; + } + + if (g_utf8_strlen(textbox->text, -1) * aud_active_skin->properties.textbox_bitmap_font_width > textbox->width) + return TRUE; + + return FALSE; +} + +void ui_skinned_textbox_set_xfont(GtkWidget *widget, gboolean use_xfont, const gchar * fontname) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + gint ascent, descent; + + g_return_if_fail(textbox != NULL); + + if (priv->font) { + pango_font_description_free(priv->font); + priv->font = NULL; + } + + textbox->y = priv->nominal_y; + textbox->height = priv->nominal_height; + + /* Make sure the pixmap is regenerated */ + if (priv->pixbuf_text) { + g_free(priv->pixbuf_text); + priv->pixbuf_text = NULL; + } + + if (!use_xfont || strlen(fontname) == 0) + return; + + priv->font = pango_font_description_from_string(fontname); + priv->fontname = g_strdup(fontname); + + text_get_extents(fontname, + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ", + NULL, NULL, &ascent, &descent); + priv->font_ascent = ascent; + priv->font_descent = descent; + + + if (priv->font == NULL) + return; + + textbox->height = priv->font_ascent; + if (textbox->height > priv->nominal_height) + textbox->y -= (textbox->height - priv->nominal_height) / 2; + else + textbox->height = priv->nominal_height; +} + +void ui_skinned_textbox_set_text(GtkWidget *widget, const gchar *text) { + g_return_if_fail(text != NULL); + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (!strcmp(textbox->text, text)) + return; + if (textbox->text) + g_free(textbox->text); + + textbox->text = aud_str_to_utf8(text); + priv->scroll_back = FALSE; + gtk_widget_queue_draw(GTK_WIDGET(textbox)); +} + +static void textbox_generate_xfont_pixmap(UiSkinnedTextbox *textbox, const gchar *pixmaptext) { + /* FIXME: should operate directly on priv->pixbuf, it shouldn't use pixmap */ + gint length, i; + GdkGC *gc, *maskgc; + GdkColor *c, pattern; + GdkBitmap *mask; + PangoLayout *layout; + gint width; + GdkPixmap *pixmap; + + g_return_if_fail(textbox != NULL); + g_return_if_fail(pixmaptext != NULL); + g_return_if_fail(textbox->height > 0); + + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + length = g_utf8_strlen(pixmaptext, -1); + + text_get_extents(priv->fontname, pixmaptext, &width, NULL, NULL, NULL); + + priv->pixbuf_width = MAX(width, textbox->width); + pixmap = gdk_pixmap_new(mainwin->window, priv->pixbuf_width, + textbox->height, + gdk_rgb_get_visual()->depth); + gc = gdk_gc_new(pixmap); + c = skin_get_color(aud_active_skin, SKIN_TEXTBG); + for (i = 0; i < textbox->height; i++) { + gdk_gc_set_foreground(gc, &c[6 * i / textbox->height]); + gdk_draw_line(pixmap, gc, 0, i, priv->pixbuf_width, i); + } + + mask = gdk_pixmap_new(mainwin->window, priv->pixbuf_width, textbox->height, 1); + maskgc = gdk_gc_new(mask); + pattern.pixel = 0; + gdk_gc_set_foreground(maskgc, &pattern); + + gdk_draw_rectangle(mask, maskgc, TRUE, 0, 0, priv->pixbuf_width, textbox->height); + pattern.pixel = 1; + gdk_gc_set_foreground(maskgc, &pattern); + + gdk_gc_set_foreground(gc, skin_get_color(aud_active_skin, SKIN_TEXTFG)); + + layout = gtk_widget_create_pango_layout(mainwin, pixmaptext); + pango_layout_set_font_description(layout, priv->font); + + gdk_draw_layout(pixmap, gc, 0, (priv->font_descent / 2), layout); + g_object_unref(layout); + + g_object_unref(maskgc); + + gdk_gc_set_clip_mask(gc, mask); + c = skin_get_color(aud_active_skin, SKIN_TEXTFG); + for (i = 0; i < textbox->height; i++) { + gdk_gc_set_foreground(gc, &c[6 * i / textbox->height]); + gdk_draw_line(pixmap, gc, 0, i, priv->pixbuf_width, i); + } + priv->pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, gdk_colormap_get_system(), 0, 0, 0, 0, priv->pixbuf_width, textbox->height); + g_object_unref(mask); + g_object_unref(gc); +} + +static gboolean textbox_scroll(gpointer data) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(data); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (!priv->is_dragging) { + if (priv->scroll_dummy < TEXTBOX_SCROLL_WAIT) + priv->scroll_dummy++; + else { + if(config.twoway_scroll) { + if (priv->scroll_back) + priv->offset -= 1; + else + priv->offset += 1; + + if (priv->offset >= (priv->pixbuf_width - textbox->width)) { + priv->scroll_back = TRUE; + priv->scroll_dummy = 0; + priv->offset = priv->pixbuf_width - textbox->width; + } + if (priv->offset <= 0) { + priv->scroll_back = FALSE; + priv->scroll_dummy = 0; + priv->offset = 0; + } + } + else { // oneway scroll + priv->scroll_back = FALSE; + priv->offset += 1; + } + gtk_widget_queue_draw(GTK_WIDGET(textbox)); + } + } + return TRUE; +} + +static void textbox_generate_pixmap(UiSkinnedTextbox *textbox) { + gint length, i, x, y, wl; + gchar *pixmaptext; + gchar *tmp, *stxt; + + g_return_if_fail(textbox != NULL); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (priv->pixbuf) { + g_object_unref(priv->pixbuf); + priv->pixbuf = NULL; + } + + /* + * Don't reset the offset if only text after the last '(' has + * changed. This is a hack to avoid visual noice on vbr files + * where we guess the length. + */ + if (!(priv->pixbuf_text && strrchr(textbox->text, '(') && + !strncmp(priv->pixbuf_text, textbox->text, + strrchr(textbox->text, '(') - textbox->text))) + priv->offset = 0; + + g_free(priv->pixbuf_text); + priv->pixbuf_text = g_strdup(textbox->text); + + /* + * wl is the number of (partial) letters visible. Only makes + * sense when using skinned font. + */ + wl = textbox->width / 5; + if (wl * 5 != textbox->width) + wl++; + + length = g_utf8_strlen(textbox->text, -1); + + priv->is_scrollable = FALSE; + + priv->is_scrollable = ui_skinned_textbox_should_scroll(textbox); + + if (priv->is_scrollable) { + if(!config.twoway_scroll) { + pixmaptext = g_strdup_printf("%s *** ", priv->pixbuf_text); + length += 5; + } else + pixmaptext = g_strdup(priv->pixbuf_text); + } else + if (!priv->font && length <= wl) { + gint pad = wl - length; + gchar *padchars = g_strnfill(pad, ' '); + + pixmaptext = g_strconcat(priv->pixbuf_text, padchars, NULL); + g_free(padchars); + length += pad; + } else + pixmaptext = g_strdup(priv->pixbuf_text); + + if (priv->is_scrollable) { + if (priv->scroll_enabled && !priv->scroll_timeout) { + gint tag; + tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT; + priv->scroll_timeout = g_timeout_add(tag, textbox_scroll, textbox); + } + } else { + if (priv->scroll_timeout) { + g_source_remove(priv->scroll_timeout); + priv->scroll_timeout = 0; + } + priv->offset = 0; + } + + if (priv->font) { + textbox_generate_xfont_pixmap(textbox, pixmaptext); + g_free(pixmaptext); + return; + } + + priv->pixbuf_width = length * aud_active_skin->properties.textbox_bitmap_font_width; + priv->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, + priv->pixbuf_width, aud_active_skin->properties.textbox_bitmap_font_height); + + for (tmp = stxt = g_utf8_strup(pixmaptext, -1), i = 0; + tmp != NULL && i < length; i++, tmp = g_utf8_next_char(tmp)) { + gchar c = *tmp; + x = y = -1; + if (c >= 'A' && c <= 'Z') { + x = aud_active_skin->properties.textbox_bitmap_font_width * (c - 'A'); + y = 0; + } + else if (c >= '0' && c <= '9') { + x = aud_active_skin->properties.textbox_bitmap_font_width * (c - '0'); + y = aud_active_skin->properties.textbox_bitmap_font_height; + } + else + textbox_handle_special_char(tmp, &x, &y); + + skin_draw_pixbuf(GTK_WIDGET(textbox), aud_active_skin, + priv->pixbuf, priv->skin_index, + x, y, i * aud_active_skin->properties.textbox_bitmap_font_width, 0, + aud_active_skin->properties.textbox_bitmap_font_width, + aud_active_skin->properties.textbox_bitmap_font_height); + } + g_free(stxt); + g_free(pixmaptext); +} + +void ui_skinned_textbox_set_scroll(GtkWidget *widget, gboolean scroll) { + g_return_if_fail(widget != NULL); + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + priv->scroll_enabled = scroll; + if (priv->scroll_enabled && priv->is_scrollable && priv->scroll_allowed) { + gint tag; + tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT; + if (priv->scroll_timeout) { + g_source_remove(priv->scroll_timeout); + priv->scroll_timeout = 0; + } + priv->scroll_timeout = g_timeout_add(tag, textbox_scroll, textbox); + + } else { + + if (priv->scroll_timeout) { + g_source_remove(priv->scroll_timeout); + priv->scroll_timeout = 0; + } + + priv->offset = 0; + gtk_widget_queue_draw(GTK_WIDGET(textbox)); + } +} + +static void textbox_handle_special_char(gchar *c, gint * x, gint * y) { + gint tx, ty; + + switch (*c) { + case '"': + tx = 26; + ty = 0; + break; + case '\r': + tx = 10; + ty = 1; + break; + case ':': + case ';': + tx = 12; + ty = 1; + break; + case '(': + tx = 13; + ty = 1; + break; + case ')': + tx = 14; + ty = 1; + break; + case '-': + tx = 15; + ty = 1; + break; + case '`': + case '\'': + tx = 16; + ty = 1; + break; + case '!': + tx = 17; + ty = 1; + break; + case '_': + tx = 18; + ty = 1; + break; + case '+': + tx = 19; + ty = 1; + break; + case '\\': + tx = 20; + ty = 1; + break; + case '/': + tx = 21; + ty = 1; + break; + case '[': + tx = 22; + ty = 1; + break; + case ']': + tx = 23; + ty = 1; + break; + case '^': + tx = 24; + ty = 1; + break; + case '&': + tx = 25; + ty = 1; + break; + case '%': + tx = 26; + ty = 1; + break; + case '.': + case ',': + tx = 27; + ty = 1; + break; + case '=': + tx = 28; + ty = 1; + break; + case '$': + tx = 29; + ty = 1; + break; + case '#': + tx = 30; + ty = 1; + break; + case '?': + tx = 3; + ty = 2; + break; + case '*': + tx = 4; + ty = 2; + break; + default: + tx = 29; + ty = 0; + break; + } + + const gchar *change[] = {"Ä„", "A", "Ę", "E", "Ć", "C", "Å", "L", "Ó", "O", "Åš", "S", "Å»", "Z", "Ź", "Z", + "Ń", "N", "Ãœ", "U", NULL}; + int i; + for (i = 0; change[i]; i+=2) { + if (!strncmp(c, change[i], strlen(change[i]))) { + tx = (*change[i+1] - 'A'); + break; + } + } + + /* those are commonly included into skins */ + if (!strncmp(c, "Ã…", strlen("Ã…"))) { + tx = 0; + ty = 2; + } else if (!strncmp(c, "Ö", strlen("Ö"))) { + tx = 1; + ty = 2; + } else if (!strncmp(c, "Ä", strlen("Ä"))) { + tx = 2; + ty = 2; + } + + *x = tx * aud_active_skin->properties.textbox_bitmap_font_width; + *y = ty * aud_active_skin->properties.textbox_bitmap_font_height; +} + +void ui_skinned_textbox_move_relative(GtkWidget *widget, gint x, gint y) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); + priv->move_x += x; + priv->move_y += y; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_textbox.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,71 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_SKINNED_TEXTBOX_H +#define AUDACIOUS_UI_SKINNED_TEXTBOX_H + +#include <gtk/gtk.h> +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_TEXTBOX(obj) GTK_CHECK_CAST (obj, ui_skinned_textbox_get_type (), UiSkinnedTextbox) +#define UI_SKINNED_TEXTBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_textbox_get_type (), UiSkinnedTextboxClass) +#define UI_SKINNED_IS_TEXTBOX(obj) GTK_CHECK_TYPE (obj, ui_skinned_textbox_get_type ()) + +typedef struct _UiSkinnedTextbox UiSkinnedTextbox; +typedef struct _UiSkinnedTextboxClass UiSkinnedTextboxClass; + +struct _UiSkinnedTextbox { + GtkWidget widget; + + gint x, y, width, height; + gchar *text; +}; + +struct _UiSkinnedTextboxClass { + GtkWidgetClass parent_class; + void (* clicked) (UiSkinnedTextbox *textbox); + void (* double_clicked) (UiSkinnedTextbox *textbox); + void (* right_clicked) (UiSkinnedTextbox *textbox); + void (* scaled) (UiSkinnedTextbox *textbox); + void (* redraw) (UiSkinnedTextbox *textbox); +}; + +GtkWidget* ui_skinned_textbox_new (GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si); +GtkType ui_skinned_textbox_get_type(void); +void ui_skinned_textbox_set_xfont(GtkWidget *widget, gboolean use_xfont, const gchar * fontname); +void ui_skinned_textbox_set_text(GtkWidget *widget, const gchar *text); +void ui_skinned_textbox_set_scroll(GtkWidget *widget, gboolean scroll); +void ui_skinned_textbox_move_relative(GtkWidget *widget, gint x, gint y); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_TEXTBOX_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_window.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,286 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "platform/smartinclude.h" +#include "ui_skin.h" +#include "skins_cfg.h" + +#include <gtk/gtkmain.h> +#include <glib-object.h> +#include <glib/gmacros.h> +#include <gtk/gtkmarshal.h> +#include <gtk/gtkwindow.h> +#include <string.h> + +#include <audacious/plugin.h> +#include "ui_dock.h" +#include "ui_skinned_window.h" + +static void ui_skinned_window_class_init(SkinnedWindowClass *klass); +static void ui_skinned_window_init(GtkWidget *widget); +static GtkWindowClass *parent = NULL; + +GType +ui_skinned_window_get_type(void) +{ + static GType window_type = 0; + + if (!window_type) + { + static const GTypeInfo window_info = + { + sizeof (SkinnedWindowClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ui_skinned_window_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SkinnedWindow), + 0, /* n_preallocs */ + (GInstanceInitFunc) ui_skinned_window_init + }; + + window_type = + g_type_register_static (GTK_TYPE_WINDOW, "SkinnedWindow", + &window_info, 0); + } + + return window_type; +} + +static void +ui_skinned_window_map(GtkWidget *widget) +{ + (* GTK_WIDGET_CLASS (parent)->map) (widget); + + SkinnedWindow *window = SKINNED_WINDOW(widget); + if (window->type == WINDOW_MAIN) + gtk_widget_shape_combine_mask(widget, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + config.player_shaded), 0, 0); + else if (window->type == WINDOW_EQ) + gtk_widget_shape_combine_mask(widget, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + config.equalizer_shaded), 0, 0); + + gtk_window_set_keep_above(GTK_WINDOW(widget), config.always_on_top); +} + +static gboolean +ui_skinned_window_motion_notify_event(GtkWidget *widget, + GdkEventMotion *event) +{ + if (dock_is_moving(GTK_WINDOW(widget))) + dock_move_motion(GTK_WINDOW(widget), event); + + return FALSE; +} + +static gboolean ui_skinned_window_focus_in(GtkWidget *widget, GdkEventFocus *focus) { + gboolean val = GTK_WIDGET_CLASS (parent)->focus_in_event (widget, focus); + gtk_widget_queue_draw(widget); + return val; +} + +static gboolean ui_skinned_window_focus_out(GtkWidget *widget, GdkEventFocus *focus) { + gboolean val = GTK_WIDGET_CLASS (parent)->focus_out_event (widget, focus); + gtk_widget_queue_draw(widget); + return val; +} + +static gboolean ui_skinned_window_button_press(GtkWidget *widget, GdkEventButton *event) { + if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + (config.easy_move || config.equalizer_shaded || (event->y / config.scale_factor) < 14)) { + dock_move_press(get_dock_window_list(), GTK_WINDOW(widget), + event, SKINNED_WINDOW(widget)->type == WINDOW_MAIN ? TRUE : FALSE); + } + + return TRUE; +} + +static gboolean ui_skinned_window_button_release(GtkWidget *widget, GdkEventButton *event) { + if (dock_is_moving(GTK_WINDOW(widget))) + dock_move_release(GTK_WINDOW(widget)); + + return TRUE; +} + +static gboolean ui_skinned_window_expose(GtkWidget *widget, GdkEventExpose *event) { + SkinnedWindow *window = SKINNED_WINDOW(widget); + + GdkPixbuf *obj = NULL; + + gint width = 0, height = 0; + switch (window->type) { + case WINDOW_MAIN: + width = aud_active_skin->properties.mainwin_width; + height = aud_active_skin->properties.mainwin_height; + break; + case WINDOW_EQ: + width = 275 * (config.scaled ? config.scale_factor : 1); + height = 116 * (config.scaled ? config.scale_factor : 1) ; + break; + case WINDOW_PLAYLIST: + width = playlistwin_get_width(); + height = config.playlist_height; + break; + default: + return FALSE; + } + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); + + gboolean focus = gtk_window_has_toplevel_focus(GTK_WINDOW(widget)); + + switch (window->type) { + case WINDOW_MAIN: + skin_draw_pixbuf(widget, aud_active_skin, obj,SKIN_MAIN, 0, 0, 0, 0, width, height); + skin_draw_mainwin_titlebar(aud_active_skin, obj, config.player_shaded, focus || !config.dim_titlebar); + break; + case WINDOW_EQ: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 0, 0, 0, width, height); + if (focus || !config.dim_titlebar) { + if (!config.equalizer_shaded) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 134, 0, 0, width, 14); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQ_EX, 0, 0, 0, 0, width, 14); + } else { + if (!config.equalizer_shaded) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 149, 0, 0, width, 14); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQ_EX, 0, 15, 0, 0, width, 14); + } + break; + case WINDOW_PLAYLIST: + focus |= !config.dim_titlebar; + if (config.playlist_shaded) { + skin_draw_playlistwin_shaded(aud_active_skin, obj, width, focus); + } else { + skin_draw_playlistwin_frame(aud_active_skin, obj, width, config.playlist_height, focus); + } + break; + } + + ui_skinned_widget_draw(GTK_WIDGET(window), obj, width, height, + window->type != WINDOW_PLAYLIST && config.scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void +ui_skinned_window_class_init(SkinnedWindowClass *klass) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) klass; + + parent = gtk_type_class(gtk_window_get_type()); + + widget_class->motion_notify_event = ui_skinned_window_motion_notify_event; + widget_class->expose_event = ui_skinned_window_expose; + widget_class->focus_in_event = ui_skinned_window_focus_in; + widget_class->focus_out_event = ui_skinned_window_focus_out; + widget_class->button_press_event = ui_skinned_window_button_press; + widget_class->button_release_event = ui_skinned_window_button_release; + widget_class->map = ui_skinned_window_map; +} + +void +ui_skinned_window_hide(SkinnedWindow *window) +{ + g_return_if_fail(SKINNED_CHECK_WINDOW(window)); + + gtk_window_get_position(GTK_WINDOW(window), &window->x, &window->y); + gtk_widget_hide(GTK_WIDGET(window)); +} + +void +ui_skinned_window_show(SkinnedWindow *window) +{ + g_return_if_fail(SKINNED_CHECK_WINDOW(window)); + + gtk_window_move(GTK_WINDOW(window), window->x, window->y); + gtk_widget_show_all(GTK_WIDGET(window)); +} + +static void +ui_skinned_window_init(GtkWidget *widget) +{ + SkinnedWindow *window; + window = SKINNED_WINDOW(widget); + window->x = -1; + window->y = -1; +} + +GtkWidget * +ui_skinned_window_new(const gchar *wmclass_name) +{ + GtkWidget *widget = g_object_new(ui_skinned_window_get_type(), NULL); + GtkWindow *window = GTK_WINDOW(widget); + + window->type = SKINNED_WINDOW_TYPE; + + if (wmclass_name) + gtk_window_set_wmclass(GTK_WINDOW(widget), wmclass_name, "Audacious"); + + gtk_widget_add_events(GTK_WIDGET(widget), + GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK | + GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK); + gtk_widget_realize(GTK_WIDGET(widget)); + + set_dock_window_list(dock_window_set_decorated(get_dock_window_list(), + GTK_WINDOW(widget), + config.show_wm_decorations)); + gtk_widget_set_app_paintable(GTK_WIDGET(widget), TRUE); + gdk_window_set_back_pixmap(widget->window, NULL, FALSE); + gtk_widget_shape_combine_mask(widget, NULL, 0, 0); + + if (!strcmp(wmclass_name, "player")) + SKINNED_WINDOW(widget)->type = WINDOW_MAIN; + if (!strcmp(wmclass_name, "equalizer")) + SKINNED_WINDOW(widget)->type = WINDOW_EQ; + if (!strcmp(wmclass_name, "playlist")) + SKINNED_WINDOW(widget)->type = WINDOW_PLAYLIST; + + /* GtkFixed hasn't got its GdkWindow, this means that it can be used to + display widgets while the logo below will be displayed anyway; + however fixed positions are not that great, cause the button sizes may (will) + vary depending on the gtk style used, so it's not possible to center + them unless a fixed width and heigth is forced (and this may bring to cutted + text if someone, i.e., uses a big font for gtk widgets); + other types of container most likely have their GdkWindow, this simply + means that the logo must be drawn on the container widget, instead of the + window; otherwise, it won't be displayed correctly */ + SKINNED_WINDOW(widget)->fixed = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(widget), GTK_WIDGET(SKINNED_WINDOW(widget)->fixed)); + return widget; +} + +void ui_skinned_window_draw_all(GtkWidget *widget) { + if (SKINNED_WINDOW(widget)->type == WINDOW_MAIN) + mainwin_refresh_hints(); + + gtk_widget_queue_draw(widget); + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(widget)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + gtk_widget_queue_draw(child); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_skinned_window.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * + * 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; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef UI_SKINNED_WINDOW_H +#define UI_SKINNED_WINDOW_H + +#define SKINNED_WINDOW(obj) GTK_CHECK_CAST (obj, ui_skinned_window_get_type (), SkinnedWindow) +#define SKINNED_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_window_get_type (), SkinnedWindowClass) +#define SKINNED_CHECK_WINDOW(obj) GTK_CHECK_TYPE (obj, ui_skinned_window_get_type ()) +#define SKINNED_TYPE_WINDOW (ui_skinned_window_get_type()) + +#ifdef GDK_WINDOWING_QUARTZ +# define SKINNED_WINDOW_TYPE GTK_WINDOW_POPUP +#else +# define SKINNED_WINDOW_TYPE GTK_WINDOW_TOPLEVEL +#endif + +enum { + WINDOW_MAIN, + WINDOW_EQ, + WINDOW_PLAYLIST +}; + +typedef struct _SkinnedWindow SkinnedWindow; +typedef struct _SkinnedWindowClass SkinnedWindowClass; + +struct _SkinnedWindow +{ + GtkWindow window; + + GtkWidget *canvas; + gint x,y; + + gint type; + GtkWidget *fixed; +}; + +struct _SkinnedWindowClass +{ + GtkWindowClass parent_class; +}; + +extern GType ui_skinned_window_get_type(void); +extern GtkWidget *ui_skinned_window_new(const gchar *wmclass_name); +extern void ui_skinned_window_draw_all(GtkWidget *widget); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_svis.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,546 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Audacious development team. + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skin.h" +#include "ui_svis.h" +#include "ui_vis.h" +#include "util.h" +#include "skins_cfg.h" +#include <audacious/plugin.h> +#include <string.h> +#include <ctype.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkmarshal.h> +#include <gtk/gtkimage.h> + +#define UI_TYPE_SVIS (ui_svis_get_type()) + +static gint svis_redraw_delays[] = { 1, 2, 4, 8 }; + +/* FIXME: Are the svis_scope_colors correct? */ +static guint8 svis_scope_colors[] = { 20, 19, 18, 19, 20 }; +static guint8 svis_vu_normal_colors[] = { 17, 17, 17, 12, 12, 12, 2, 2 }; + +#define DRAW_DS_PIXEL(ptr,value) \ + *(ptr) = (value); \ + *((ptr) + 1) = (value); \ + *((ptr) + 76) = (value); \ + *((ptr) + 77) = (value); + +#define SVIS_HEIGHT 5 +#define SVIS_WIDTH 38 + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_svis_class_init (UiSVisClass *klass); +static void ui_svis_init (UiSVis *svis); +static void ui_svis_destroy (GtkObject *object); +static void ui_svis_realize (GtkWidget *widget); +static void ui_svis_unrealize (GtkWidget *widget); +static void ui_svis_map (GtkWidget *widget); +static void ui_svis_unmap (GtkWidget *widget); +static void ui_svis_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_svis_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_svis_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_svis_toggle_scaled (UiSVis *svis); + +static GtkWidgetClass *parent_class = NULL; +static guint vis_signals[LAST_SIGNAL] = { 0 }; + +GType ui_svis_get_type() { + static GType vis_type = 0; + if (!vis_type) { + static const GTypeInfo vis_info = { + sizeof (UiSVisClass), + NULL, + NULL, + (GClassInitFunc) ui_svis_class_init, + NULL, + NULL, + sizeof (UiSVis), + 0, + (GInstanceInitFunc) ui_svis_init, + }; + vis_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSVis", &vis_info, 0); + } + + return vis_type; +} + +static void ui_svis_class_init(UiSVisClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_svis_destroy; + + widget_class->realize = ui_svis_realize; + widget_class->unrealize = ui_svis_unrealize; + widget_class->map = ui_svis_map; + widget_class->unmap = ui_svis_unmap; + widget_class->expose_event = ui_svis_expose; + widget_class->size_request = ui_svis_size_request; + widget_class->size_allocate = ui_svis_size_allocate; + + klass->scaled = ui_svis_toggle_scaled; + + vis_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSVisClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_svis_init(UiSVis *svis) { + +} + +GtkWidget* ui_svis_new(GtkWidget *fixed, gint x, gint y) { + UiSVis *svis = g_object_new (ui_svis_get_type (), NULL); + + svis->x = x; + svis->y = y; + + svis->width = SVIS_WIDTH; + svis->height = SVIS_HEIGHT; + + svis->fixed = fixed; + svis->scaled = FALSE; + + svis->visible_window = TRUE; + svis->event_window = NULL; + + gtk_fixed_put(GTK_FIXED(svis->fixed), GTK_WIDGET(svis), svis->x, svis->y); + + return GTK_WIDGET(svis); +} + +static void ui_svis_destroy(GtkObject *object) { + UiSVis *svis; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_IS_SVIS (object)); + + svis = UI_SVIS (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_svis_realize(GtkWidget *widget) { + UiSVis *svis; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_IS_SVIS(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + svis = UI_SVIS(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; + + if (svis->visible_window) + { + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + GTK_WIDGET_UNSET_FLAGS(widget, GTK_NO_WINDOW); + gdk_window_set_user_data(widget->window, widget); + } + else + { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + + attributes.wclass = GDK_INPUT_ONLY; + attributes_mask = GDK_WA_X | GDK_WA_Y; + svis->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); + GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(svis->event_window, widget); + } + + widget->style = gtk_style_attach(widget->style, widget->window); +} + +static void ui_svis_unrealize(GtkWidget *widget) { + UiSVis *svis; + svis = UI_SVIS(widget); + + if ( svis->event_window != NULL ) + { + gdk_window_set_user_data( svis->event_window , NULL ); + gdk_window_destroy( svis->event_window ); + svis->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void ui_svis_map(GtkWidget *widget) +{ + UiSVis *svis; + svis = UI_SVIS(widget); + + if (svis->event_window != NULL) + gdk_window_show (svis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->map) + (* GTK_WIDGET_CLASS (parent_class)->map) (widget); +} + +static void ui_svis_unmap (GtkWidget *widget) +{ + UiSVis *svis; + svis = UI_SVIS(widget); + + if (svis->event_window != NULL) + gdk_window_hide (svis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->unmap) + (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); +} + +static void ui_svis_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSVis *svis = UI_SVIS(widget); + + requisition->width = svis->width * (svis->scaled ? config.scale_factor : 1); + requisition->height = svis->height*(svis->scaled ? config.scale_factor : 1); +} + +static void ui_svis_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSVis *svis = UI_SVIS (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (svis->scaled ? config.scale_factor : 1 ); + widget->allocation.y *= (svis->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + { + if (svis->event_window != NULL) + gdk_window_move_resize(svis->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + else + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + } + + svis->x = widget->allocation.x/(svis->scaled ? config.scale_factor : 1); + svis->y = widget->allocation.y/(svis->scaled ? config.scale_factor : 1); +} + +static gboolean ui_svis_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_IS_SVIS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSVis *svis = UI_SVIS (widget); + + gint x, y, h; + guchar svis_color[24][3]; + guchar rgb_data[SVIS_WIDTH * 2 * SVIS_HEIGHT * 2], *ptr, c; + guint32 colors[24]; + GdkRgbCmap *cmap; + + if (!GTK_WIDGET_VISIBLE(widget)) + return FALSE; + + if (!svis->visible_window) + return FALSE; + + skin_get_viscolor(aud_active_skin, svis_color); + for (y = 0; y < 24; y++) { + colors[y] = + svis_color[y][0] << 16 | svis_color[y][1] << 8 | svis_color[y][2]; + } + cmap = gdk_rgb_cmap_new(colors, 24); + + if (!config.scaled) { + memset(rgb_data, 0, SVIS_WIDTH * SVIS_HEIGHT); + if (config.vis_type == VIS_ANALYZER && !audacious_drct_get_paused() && audacious_drct_get_playing()){ + for(y=0; y < SVIS_HEIGHT; y++){ + if (config.analyzer_type == ANALYZER_BARS){ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + rgb_data[x*3+ (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; + rgb_data[x*3+1 + (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; + + } + } + } + else{ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + rgb_data[x + (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; + } + } + } + } + } + else if (config.vis_type == VIS_VOICEPRINT){ + switch (config.vu_mode) { + case VU_NORMAL: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * 38); + h = (svis->data[y] * 7) / 37; + for (x = 0; x < h; x++, ptr += 5) { + c = svis_vu_normal_colors[x]; + *(ptr) = c; + *(ptr + 1) = c; + *(ptr + 2) = c; + *(ptr + 38) = c; + *(ptr + 39) = c; + *(ptr + 40) = c; + } + } + break; + case VU_SMOOTH: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * SVIS_WIDTH); + for (x = 0; x < svis->data[y]; x++, ptr++) { + c = 17 - ((x * 15) / 37); + *(ptr) = c; + *(ptr + 38) = c; + } + } + break; + } + } + else if (config.vis_type == VIS_SCOPE) { + for (x = 0; x < 38; x++) { + h = svis->data[x << 1] / 3; + ptr = rgb_data + ((4 - h) * 38) + x; + *ptr = svis_scope_colors[h]; + } + } + + } + else { /*svis scaling, this needs some work, since a lot of stuff is hardcoded --majeru*/ + + memset(rgb_data, 0, SVIS_WIDTH * config.scale_factor * SVIS_HEIGHT * aud_cfg->scale_factor); + if (config.vis_type == VIS_ANALYZER && !audacious_drct_get_paused() && audacious_drct_get_playing()){ + for(y=0; y < SVIS_HEIGHT; y++){ + if (config.analyzer_type == ANALYZER_BARS){ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + ptr = rgb_data + x * 6 + (SVIS_HEIGHT * 2 - y * 2) * SVIS_WIDTH *2; + DRAW_DS_PIXEL(ptr, 23); + DRAW_DS_PIXEL(ptr + 2, 23); + } + } + } + else{ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + ptr = rgb_data + x * 2 + (SVIS_HEIGHT * 2 - y * 2) * SVIS_WIDTH * 2; + DRAW_DS_PIXEL(ptr, 23); + } + } + } + } + } + else if (config.vis_type == VIS_VOICEPRINT){ + switch (config.vu_mode) { + case VU_NORMAL: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * 152); + h = (svis->data[y] * 8) / 37; + for (x = 0; x < h; x++, ptr += 10) { + c = svis_vu_normal_colors[x]; + DRAW_DS_PIXEL(ptr, c); + DRAW_DS_PIXEL(ptr + 2, c); + DRAW_DS_PIXEL(ptr + 4, c); + DRAW_DS_PIXEL(ptr + 152, c); + DRAW_DS_PIXEL(ptr + 154, c); + DRAW_DS_PIXEL(ptr + 156, c); + } + } + break; + case VU_SMOOTH: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * 152); + for (x = 0; x < svis->data[y]; x++, ptr += 2) { + c = 17 - ((x * 15) / 37); + DRAW_DS_PIXEL(ptr, c); + DRAW_DS_PIXEL(ptr + 152, c); + } + } + break; + } + } + else if (config.vis_type == VIS_SCOPE) { + for (x = 0; x < 38; x++) { + h = svis->data[x << 1] / 3; + ptr = rgb_data + ((4 - h) * 152) + (x << 1); + *ptr = svis_scope_colors[h]; + *(ptr + 1) = svis_scope_colors[h]; + *(ptr + 76) = svis_scope_colors[h]; + *(ptr + 77) = svis_scope_colors[h]; + } + } + + + } + + GdkPixmap *obj = NULL; + GdkGC *gc; + obj = gdk_pixmap_new(NULL, svis->width* ( svis->scaled ? config.scale_factor : 1), + svis->height*(svis->scaled ? config.scale_factor : 1), gdk_rgb_get_visual()->depth); + gc = gdk_gc_new(obj); + + if (!svis->scaled) { + gdk_draw_indexed_image(obj, gc, 0, 0, svis->width, svis->height, + GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, + 38, cmap); + } else { + gdk_draw_indexed_image(obj, gc, + 0 << 1, 0 << 1, + svis->width << 1, svis->height << 1, + GDK_RGB_DITHER_NONE, (guchar *) rgb_data, + 76, cmap); + } + + gdk_rgb_cmap_free(cmap); + gdk_draw_drawable (widget->window, gc, obj, 0, 0, 0, 0, + svis->width*(svis->scaled ? config.scale_factor : 1), + svis->height*(svis->scaled ? config.scale_factor : 1)); + g_object_unref(obj); + g_object_unref(gc); + + return FALSE; +} + +static void ui_svis_toggle_scaled(UiSVis *svis) { + GtkWidget *widget = GTK_WIDGET (svis); + svis->scaled = !svis->scaled; + + gtk_widget_set_size_request(widget, svis->width* config.scale_factor, svis->height * aud_cfg->scale_factor); + + gtk_widget_queue_draw(widget); +} + +void ui_svis_set_visible(GtkWidget *widget, gboolean window_is_visible) +{ + UiSVis *svis; + gboolean widget_is_visible; + + g_return_if_fail(UI_IS_SVIS(widget)); + + svis = UI_SVIS (widget); + widget_is_visible = GTK_WIDGET_VISIBLE(widget); + + svis->visible_window = window_is_visible; + + if (GTK_WIDGET_REALIZED (widget)) + { + if ( widget_is_visible ) + gtk_widget_hide(widget); + + gtk_widget_unrealize(widget); + gtk_widget_realize(widget); + + if ( widget_is_visible ) + gtk_widget_show(widget); + } + + if (widget_is_visible) + gtk_widget_queue_resize(widget); +} + +void ui_svis_clear_data(GtkWidget *widget) { + gint i; + + UiSVis *svis = UI_SVIS (widget); + + for (i = 0; i < 75; i++) { + svis->data[i] = (config.vis_type == VIS_SCOPE) ? 6 : 0; + } +} + +void ui_svis_timeout_func(GtkWidget *widget, guchar * data) { + UiSVis *svis = UI_SVIS (widget); + static GTimer *timer = NULL; + gulong micros = 9999999; + gboolean falloff = FALSE; + gint i; + + if (!timer) { + timer = g_timer_new(); + g_timer_start(timer); + } + else { + g_timer_elapsed(timer, µs); + if (micros > 14000) + g_timer_reset(timer); + + } + + if (config.vis_type == VIS_VOICEPRINT) { + if (micros > 14000) + falloff = TRUE; + + for (i = 0; i < 2; i++) { + if (falloff || data) { + if (data && data[i] > svis->data[i]) + svis->data[i] = data[i]; + else if (falloff) { + if (svis->data[i] >= 2) + svis->data[i] -= 2; + else + svis->data[i] = 0; + } + } + + } + } + else if (data) { + for (i = 0; i < 75; i++) + svis->data[i] = data[i]; + } + + if (micros > 14000) { + if (!svis->refresh_delay) { + gtk_widget_queue_draw(widget); + svis->refresh_delay = svis_redraw_delays[config.vis_refresh]; + } + svis->refresh_delay--; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_svis.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef UISVIS_H +#define UISVIS_H + +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SVIS(obj) GTK_CHECK_CAST (obj, ui_svis_get_type (), UiSVis) +#define UI_SVIS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_svis_get_type (), UiSVisClass) +#define UI_IS_SVIS(obj) GTK_CHECK_TYPE (obj, ui_svis_get_type ()) + +typedef struct _UiSVis UiSVis; +typedef struct _UiSVisClass UiSVisClass; + +struct _UiSVis { + GtkWidget widget; + + gint x, y, width, height; + gint data[75]; + gint refresh_delay; + gboolean scaled; + GtkWidget *fixed; + gboolean visible_window; + GdkWindow *event_window; +}; + +struct _UiSVisClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSVis *vis); +}; + +GtkWidget* ui_svis_new (GtkWidget *fixed, gint x, gint y); +GtkType ui_svis_get_type(void); +void ui_svis_clear_data(GtkWidget *widget); +void ui_svis_timeout_func(GtkWidget *widget, guchar * data); +void ui_svis_set_visible(GtkWidget *widget, gboolean window_is_visible); + +#ifdef __cplusplus +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_vis.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,720 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Audacious development team. + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include "ui_skin.h" +#include "ui_vis.h" +#include "util.h" +#include "skins_cfg.h" +#include <audacious/plugin.h> + +static const gfloat vis_afalloff_speeds[] = { 0.34, 0.5, 1.0, 1.3, 1.6 }; +static const gfloat vis_pfalloff_speeds[] = { 1.2, 1.3, 1.4, 1.5, 1.6 }; +static const gint vis_redraw_delays[] = { 1, 2, 4, 8 }; +static const guint8 vis_scope_colors[] = + { 21, 21, 20, 20, 19, 19, 18, 19, 19, 20, 20, 21, 21 }; +static guchar voiceprint_data[76*16]; + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_vis_class_init (UiVisClass *klass); +static void ui_vis_init (UiVis *vis); +static void ui_vis_destroy (GtkObject *object); +static void ui_vis_realize (GtkWidget *widget); +static void ui_vis_unrealize (GtkWidget *widget); +static void ui_vis_map (GtkWidget *widget); +static void ui_vis_unmap (GtkWidget *widget); +static void ui_vis_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_vis_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_vis_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_vis_toggle_scaled (UiVis *vis); + +static GtkWidgetClass *parent_class = NULL; +static guint vis_signals[LAST_SIGNAL] = { 0 }; + +GType ui_vis_get_type() { + static GType vis_type = 0; + if (!vis_type) { + static const GTypeInfo vis_info = { + sizeof (UiVisClass), + NULL, + NULL, + (GClassInitFunc) ui_vis_class_init, + NULL, + NULL, + sizeof (UiVis), + 0, + (GInstanceInitFunc) ui_vis_init, + }; + vis_type = g_type_register_static (GTK_TYPE_WIDGET, "UiVis", &vis_info, 0); + } + + return vis_type; +} + +static void ui_vis_class_init(UiVisClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_vis_destroy; + + widget_class->realize = ui_vis_realize; + widget_class->unrealize = ui_vis_unrealize; + widget_class->map = ui_vis_map; + widget_class->unmap = ui_vis_unmap; + widget_class->expose_event = ui_vis_expose; + widget_class->size_request = ui_vis_size_request; + widget_class->size_allocate = ui_vis_size_allocate; + + klass->doubled = ui_vis_toggle_scaled; + + vis_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiVisClass, doubled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_vis_init(UiVis *vis) { + memset(voiceprint_data, 0, 16*76); +} + +GtkWidget* ui_vis_new(GtkWidget *fixed, gint x, gint y, gint width) { + UiVis *vis = g_object_new (ui_vis_get_type (), NULL); + + vis->x = x; + vis->y = y; + + vis->width = width; + vis->height = 16; + + vis->fixed = fixed; + vis->scaled = FALSE; + + vis->visible_window = TRUE; + vis->event_window = NULL; + + gtk_fixed_put(GTK_FIXED(vis->fixed), GTK_WIDGET(vis), vis->x, vis->y); + + return GTK_WIDGET(vis); +} + +static void ui_vis_destroy(GtkObject *object) { + UiVis *vis; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_IS_VIS (object)); + + vis = UI_VIS (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_vis_realize(GtkWidget *widget) { + UiVis *vis; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_IS_VIS(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + vis = UI_VIS(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; + + if (vis->visible_window) + { + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + GTK_WIDGET_UNSET_FLAGS(widget, GTK_NO_WINDOW); + gdk_window_set_user_data(widget->window, widget); + } + else + { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + + attributes.wclass = GDK_INPUT_ONLY; + attributes_mask = GDK_WA_X | GDK_WA_Y; + vis->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); + GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(vis->event_window, widget); + } + + widget->style = gtk_style_attach(widget->style, widget->window); +} + +static void ui_vis_unrealize(GtkWidget *widget) { + UiVis *vis; + vis = UI_VIS(widget); + + if ( vis->event_window != NULL ) + { + gdk_window_set_user_data( vis->event_window , NULL ); + gdk_window_destroy( vis->event_window ); + vis->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void ui_vis_map(GtkWidget *widget) +{ + UiVis *vis; + vis = UI_VIS(widget); + + if (vis->event_window != NULL) + gdk_window_show (vis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->map) + (* GTK_WIDGET_CLASS (parent_class)->map) (widget); +} + +static void ui_vis_unmap (GtkWidget *widget) +{ + UiVis *vis; + vis = UI_VIS(widget); + + if (vis->event_window != NULL) + gdk_window_hide (vis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->unmap) + (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); +} + +static void ui_vis_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiVis *vis = UI_VIS(widget); + + requisition->width = vis->width*(vis->scaled ? config.scale_factor : 1); + requisition->height = vis->height*(vis->scaled ? config.scale_factor : 1); +} + +static void ui_vis_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiVis *vis = UI_VIS (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (vis->scaled ? config.scale_factor : 1); + widget->allocation.y *= (vis->scaled ? config.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + { + if (vis->event_window != NULL) + gdk_window_move_resize(vis->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + else + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + } + + vis->x = widget->allocation.x/(vis->scaled ? config.scale_factor : 1); + vis->y = widget->allocation.y/(vis->scaled ? config.scale_factor : 1); +} + +static gboolean ui_vis_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_IS_VIS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiVis *vis = UI_VIS (widget); + + gint x, y, n, h = 0, h2; + gfloat delta; + guchar skin_col[2][3]; + guchar vis_color[24][3]; + guchar vis_voice_color[256][3], voice_c[3]; + guchar rgb_data[76 * 16 * 3 * 2 * 2], *ptr, c; + guint32 colors[24]; + GdkColor *fgc, *bgc; + GdkRgbCmap *cmap; + + if (!GTK_WIDGET_VISIBLE(widget)) + return FALSE; + + if (!vis->visible_window) + return FALSE; + + skin_get_viscolor(aud_active_skin, vis_color); + for (y = 0; y < 24; y++) { + colors[y] = + vis_color[y][0] << 16 | vis_color[y][1] << 8 | vis_color[y][2]; + } + cmap = gdk_rgb_cmap_new(colors, 24); + + if (!vis->scaled) { + if(config.vis_type == VIS_VOICEPRINT /*&& aud_cfg->voiceprint_mode != VOICEPRINT_NORMAL*/){ + memset(rgb_data, 0, 76 * 16 * 3); + } + else{ + memset(rgb_data, 0, 76 * 16); + for (y = 1; y < 16; y += 2) { + ptr = rgb_data + (y * 76); + for (x = 0; x < 76; x += 2, ptr += 2) + *ptr = 1; + } + } + } + else{ + if(config.vis_type == VIS_VOICEPRINT /*&& aud_cfg->voiceprint_mode != VOICEPRINT_NORMAL*/){ + memset(rgb_data, 0, 3 * 4 * 16 * 76); + } + else{ + memset(rgb_data, 0, (guint)(76 * config.scale_factor) * 32); + for (y = 1; y < 16; y += 2) { + ptr = rgb_data + (y * (guint)(76 * 4 * config.scale_factor)); + for (x = 0; x < 76; x += 2, ptr += 4) { + *ptr = 1; + *(ptr + 1) = 1; + *(ptr + (guint)(76 * config.scale_factor)) = 1; + *(ptr + (guint)(76 * config.scale_factor)+1) = 1; + } + } + } + } + if (config.vis_type == VIS_ANALYZER) { + for (x = 0; x < 75; x++) { + if (config.analyzer_type == ANALYZER_BARS && (x % 4) == 0) + h = vis->data[x >> 2]; + else if (config.analyzer_type == ANALYZER_LINES) + h = vis->data[x]; + if (h && (config.analyzer_type == ANALYZER_LINES || + (x % 4) != 3)) { + if (!vis->scaled) { + ptr = rgb_data + ((16 - h) * 76) + x; + switch (config.analyzer_mode) { + case ANALYZER_NORMAL: + for (y = 0; y < h; y++, ptr += 76) + *ptr = 18 - h + y; + break; + case ANALYZER_FIRE: + for (y = 0; y < h; y++, ptr += 76) + *ptr = y + 2; + break; + case ANALYZER_VLINES: + for (y = 0; y < h; y++, ptr += 76) + *ptr = 18 - h; + break; + } + } + else{ + ptr = rgb_data + ((16 - h) * (guint)(76 * 4 * config.scale_factor)) + (guint)(x * aud_cfg->scale_factor); + switch (config.analyzer_mode) { + case ANALYZER_NORMAL: + for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * config.scale_factor)) { + *ptr = 18 - h + y; + *(ptr + 1) = 18 - h + y; + *(ptr + (guint)(76 * config.scale_factor)) = 18 - h + y; + *(ptr + (guint)(76 * config.scale_factor)+1) = 18 - h + y; + } + break; + case ANALYZER_FIRE: + for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * config.scale_factor)) { + *ptr = y + 2; + *(ptr + 1) = y + 2; + *(ptr + (guint)(76 * config.scale_factor)) = y + 2; + *(ptr + (guint)(76 * config.scale_factor)+1) = y + 2; + } + break; + case ANALYZER_VLINES: + for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * config.scale_factor)) { + *ptr = 18 - h; + *(ptr + 1) = 18 - h; + *(ptr + (guint)(76 * config.scale_factor)) = 18 - h; + *(ptr + (guint)(76 * config.scale_factor)+1) = 18 - h; + } + + break; + } + } + } + } + if (config.analyzer_peaks) { + for (x = 0; x < 75; x++) { + if (config.analyzer_type == ANALYZER_BARS && (x % 4) == 0) + h = vis->peak[x >> 2]; + else if (config.analyzer_type == ANALYZER_LINES) + h = vis->peak[x]; + if (h && (config.analyzer_type == ANALYZER_LINES || (x % 4) != 3)){ + + if (!vis->scaled) { + rgb_data[(16 - h) * 76 + x] = 23; + } + else{ + ptr = rgb_data + (16 - h) * (guint)(76 * 4 * config.scale_factor) + (guint)(x * aud_cfg->scale_factor); + *ptr = 23; + *(ptr + 1) = 23; + *(ptr + (guint)(76 * config.scale_factor)) = 23; + *(ptr + (guint)(76 * config.scale_factor)+1) = 23; + } + } + } + } + } + else if (config.vis_type == VIS_VOICEPRINT) { + if(!audacious_drct_get_paused() && audacious_drct_get_playing()){/*Don't scroll when it's paused or stopped*/ + for (y = 0; y < 16; y ++) + for (x = 75; x > 0; x--) + voiceprint_data[x + y * 76] = voiceprint_data[x-1+y*76]; + for(y=0;y<16;y++) + voiceprint_data[y * 76] = vis->data[y]; + } + if(audacious_drct_get_playing()){ /*Only draw the data if we're playing*/ + if(config.voiceprint_mode == VOICEPRINT_NORMAL){ + /* Create color gradient from the skin's background- and foreground color*/ + fgc = skin_get_color(aud_active_skin, SKIN_TEXTFG); + bgc = skin_get_color(aud_active_skin, SKIN_TEXTBG); + skin_col[0][0] = fgc->red >> 8; + skin_col[0][1] = fgc->green >> 8; + skin_col[0][2] = fgc->blue >> 8; + skin_col[1][0] = bgc->red >> 8; + skin_col[1][1] = bgc->green >> 8; + skin_col[1][2] = bgc->blue >> 8; + for(n=0;n<3;n++){ + for(x=0;x<256;x++){ + if(skin_col[0][n] > skin_col[1][n]){ + delta = (gfloat)(skin_col[0][n] - skin_col[1][n]) / 256.0; + vis_voice_color[x][n] = skin_col[1][n] + (gfloat)(delta * x); + } + else if(skin_col[0][n] == skin_col[1][n]){ + vis_voice_color[x][n] = skin_col[0][n]; + } + else{ + delta = (gfloat)(skin_col[1][n] - skin_col[0][n]) / 256.0; + vis_voice_color[x][n] = skin_col[1][n] - (gfloat)(delta * x); + } + } + } + } + for (y = 0; y < 16; y ++){ + for (x = 0; x < 76; x++){ + guint8 d = voiceprint_data[x + y*76]; + + if(config.voiceprint_mode == VOICEPRINT_NORMAL){ + voice_c[0] = vis_voice_color[d][0]; + voice_c[1] = vis_voice_color[d][1]; + voice_c[2] = vis_voice_color[d][2]; + } + else if(config.voiceprint_mode == VOICEPRINT_FIRE){ + voice_c[0] = d < 64 ? (d * 2) : 255; + voice_c[1] = d < 64 ? 0 : (d < 128 ? (d-64) * 2 : 255); + voice_c[2] = d < 128 ? 0 : (d-128) * 2; + /* Test for black->blue->green->red. Isn't pretty, though... + voice_c[0] = d > 192 ? (d - 192) << 2 : 0; + voice_c[1] = d > 64 ? (d < 128 ? (d - 64) << 2 : (d < 192 ? (192 - d) << 2 : 0)) : 0; + voice_c[2] = d < 64 ? d << 2 : (d < 128 ? (128 - d) << 2 : 0); + */ + } + else if(config.voiceprint_mode == VOICEPRINT_ICE){ + voice_c[0] = d; + voice_c[1] = d < 128 ? d * 2 : 255; + voice_c[2] = d < 64 ? d * 4 : 255; + } + if(!vis->scaled){ + for(n=0;n<3;n++) + rgb_data[x * 3 + y * 76*3+n] = voice_c[n]; + } + else{ + ptr = rgb_data + (guint)(x * 3 * config.scale_factor) + (guint) (y * 76 * 3 * aud_cfg->scale_factor); + for(n=0;n<3;n++) + { + *(ptr + n) = voice_c[n]; + *(ptr + n + 3) = voice_c[n]; + *(ptr + (guint)(n + 76 * config.scale_factor * 3)) = voice_c[n]; + *(ptr + (guint)(n + 3 + 76 * config.scale_factor * 3)) = voice_c[n]; + } + } + } + } + } + } + if (config.vis_type == VIS_SCOPE) { + for (x = 0; x < 75; x++) { + switch (config.scope_mode) { + case SCOPE_DOT: + h = vis->data[x]; + if (!vis->scaled) { + ptr = rgb_data + ((14 - h) * 76) + x; + *ptr = vis_scope_colors[h + 1]; + }else{ + ptr = rgb_data + ((14 - h) * (guint)(76 * 4 * config.scale_factor)) + (guint)(x * aud_cfg->scale_factor); + *ptr = vis_scope_colors[h + 1]; + *(ptr + 1) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * config.scale_factor)) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * config.scale_factor)+1) = vis_scope_colors[h + 1]; + } + break; + case SCOPE_LINE: + if (x != 74) { + h = 14 - vis->data[x]; + h2 = 14 - vis->data[x + 1]; + if (h > h2) { + y = h; + h = h2; + h2 = y; + } + if (!vis->scaled) { + ptr = rgb_data + (h * 76) + x; + for (y = h; y <= h2; y++, ptr += 76) + *ptr = vis_scope_colors[y - 2]; + } + else{ + ptr = rgb_data + (h * (guint)(76 * 4 * config.scale_factor)) + (guint)(x * aud_cfg->scale_factor); + for (y = h; y <= h2; y++, ptr += (guint)(76 * 4 * config.scale_factor)) { + *ptr = vis_scope_colors[y - 2]; + *(ptr + 1) = vis_scope_colors[y - 2]; + *(ptr + (guint)(76 * config.scale_factor)) = vis_scope_colors[y - 2]; + *(ptr + (guint)(76 * config.scale_factor)+1) = vis_scope_colors[y - 2]; + } + } + } + else { + h = 14 - vis->data[x]; + if (!vis->scaled) { + ptr = rgb_data + (h * 76) + x; + *ptr = vis_scope_colors[h + 1]; + }else{ + ptr = rgb_data + (h * (guint)(76 * 4 * config.scale_factor)) + (guint)(x * aud_cfg->scale_factor); + *ptr = vis_scope_colors[h + 1]; + *(ptr + 1) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * config.scale_factor)) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * config.scale_factor)+1) = vis_scope_colors[h + 1]; + } + } + break; + case SCOPE_SOLID: + h = 14 - vis->data[x]; + h2 = 8; + c = vis_scope_colors[(gint) vis->data[x]]; + if (h > h2) { + y = h; + h = h2; + h2 = y; + } + if (!vis->scaled) { + ptr = rgb_data + (h * 76) + x; + for (y = h; y <= h2; y++, ptr += 76) + *ptr = c; + }else{ + ptr = rgb_data + (h * (guint)(76 * 4 * config.scale_factor)) + (guint)(x * aud_cfg->scale_factor); + for (y = h; y <= h2; y++, ptr += (guint)(76 * 4 * config.scale_factor)) { + *ptr = c; + *(ptr + 1) = c; + *(ptr + (guint)(76 * config.scale_factor)) = c; + *(ptr + (guint)(76 * config.scale_factor)+1) = c; + } + } + break; + } + } + } + + GdkPixmap *obj = NULL; + GdkGC *gc; + obj = gdk_pixmap_new(NULL, vis->width*(vis->scaled ? config.scale_factor : 1), vis->height*(vis->scaled ? aud_cfg->scale_factor : 1), gdk_rgb_get_visual()->depth); + gc = gdk_gc_new(obj); + + if (!vis->scaled) { + if (config.vis_type == VIS_VOICEPRINT) { + gdk_draw_rgb_image(obj, gc, 0, 0, vis->width, vis->height, + GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, + 76 * 3); + } else { + gdk_draw_indexed_image(obj, gc, 0, 0, vis->width, vis->height, + GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, + 76 , cmap); + } + } else { + if (config.vis_type == VIS_VOICEPRINT) { + gdk_draw_rgb_image(obj, gc, 0 << 1, 0 << 1, + vis->width << 1, vis->height << 1, + GDK_RGB_DITHER_NONE, (guchar *) rgb_data, + 76 * 2 * 3); + } else { + gdk_draw_indexed_image(obj, gc, 0 << 1, 0 << 1, + vis->width << 1, vis->height << 1, + GDK_RGB_DITHER_NONE, (guchar *) rgb_data, + 76 * 2 , cmap); + } + } + + gdk_draw_drawable (widget->window, gc, obj, 0, 0, 0, 0, + vis->width*(vis->scaled ? config.scale_factor : 1), vis->height*(vis->scaled ? aud_cfg->scale_factor : 1)); + g_object_unref(obj); + g_object_unref(gc); + gdk_rgb_cmap_free(cmap); + return FALSE; +} + +static void ui_vis_toggle_scaled(UiVis *vis) { + GtkWidget *widget = GTK_WIDGET (vis); + vis->scaled = !vis->scaled; + + gtk_widget_set_size_request(widget, vis->width*(vis->scaled ? config.scale_factor : 1), vis->height*(vis->scaled ? aud_cfg->scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(vis)); +} + +void ui_vis_draw_pixel(GtkWidget *widget, guchar* texture, gint x, gint y, guint8 colour) { + UiVis *vis = UI_VIS (widget); + if (vis->scaled){ + texture[y * 76 + x] = colour; + texture[y * 76 + x + 1] = colour; + texture[y * 76 * 4 + x] = colour; + texture[y * 76 * 4 + x + 1] = colour; + } else { + texture[y * 76 + x] = colour; + } +} + +void ui_vis_set_visible(GtkWidget *widget, gboolean window_is_visible) +{ + UiVis *vis; + gboolean widget_is_visible; + + g_return_if_fail(UI_IS_VIS(widget)); + + vis = UI_VIS (widget); + widget_is_visible = GTK_WIDGET_VISIBLE(widget); + + vis->visible_window = window_is_visible; + + if (GTK_WIDGET_REALIZED (widget)) + { + if ( widget_is_visible ) + gtk_widget_hide(widget); + + gtk_widget_unrealize(widget); + gtk_widget_realize(widget); + + if ( widget_is_visible ) + gtk_widget_show(widget); + } + + if (widget_is_visible) + gtk_widget_queue_resize(widget); +} + +void ui_vis_clear_data(GtkWidget *widget) { + gint i; + UiVis *vis = UI_VIS (widget); + + memset(voiceprint_data, 0, 16*76); + for (i = 0; i < 75; i++) { + vis->data[i] = (config.vis_type == VIS_SCOPE) ? 6 : 0; + vis->peak[i] = 0; + } +} + +void ui_vis_timeout_func(GtkWidget *widget, guchar * data) { + UiVis *vis = UI_VIS (widget); + static GTimer *timer = NULL; + gulong micros = 9999999; + gboolean falloff = FALSE; + gint i; + + if (!timer) { + timer = g_timer_new(); + g_timer_start(timer); + } + else { + g_timer_elapsed(timer, µs); + if (micros > 14000) + g_timer_reset(timer); + } + if (config.vis_type == VIS_ANALYZER) { + if (micros > 14000) + falloff = TRUE; + if (data || falloff) { + for (i = 0; i < 75; i++) { + if (data && data[i] > vis->data[i]) { + vis->data[i] = data[i]; + if (vis->data[i] > vis->peak[i]) { + vis->peak[i] = vis->data[i]; + vis->peak_speed[i] = 0.01; + + } + else if (vis->peak[i] > 0.0) { + vis->peak[i] -= vis->peak_speed[i]; + vis->peak_speed[i] *= + vis_pfalloff_speeds[config.peaks_falloff]; + if (vis->peak[i] < vis->data[i]) + vis->peak[i] = vis->data[i]; + if (vis->peak[i] < 0.0) + vis->peak[i] = 0.0; + } + } + else if (falloff) { + if (vis->data[i] > 0.0) { + vis->data[i] -= + vis_afalloff_speeds[config.analyzer_falloff]; + if (vis->data[i] < 0.0) + vis->data[i] = 0.0; + } + if (vis->peak[i] > 0.0) { + vis->peak[i] -= vis->peak_speed[i]; + vis->peak_speed[i] *= + vis_pfalloff_speeds[config.peaks_falloff]; + if (vis->peak[i] < vis->data[i]) + vis->peak[i] = vis->data[i]; + if (vis->peak[i] < 0.0) + vis->peak[i] = 0.0; + } + } + } + } + } + else if (config.vis_type == VIS_VOICEPRINT && data){ + for(i = 0; i < 16; i++) + { + vis->data[i] = data[15 - i]; + } + } + else if (data) { + for (i = 0; i < 75; i++) + vis->data[i] = data[i]; + } + + if (micros > 14000) { + if (!vis->refresh_delay) { + gtk_widget_queue_draw(widget); + vis->refresh_delay = vis_redraw_delays[config.vis_refresh]; + } + vis->refresh_delay--; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/ui_vis.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,98 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef UIVIS_H +#define UIVIS_H + +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_VIS(obj) GTK_CHECK_CAST (obj, ui_vis_get_type (), UiVis) +#define UI_VIS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_vis_get_type (), UiVisClass) +#define UI_IS_VIS(obj) GTK_CHECK_TYPE (obj, ui_vis_get_type ()) + +typedef enum { + VIS_ANALYZER, VIS_SCOPE, VIS_VOICEPRINT, VIS_OFF +} VisType; + +typedef enum { + ANALYZER_NORMAL, ANALYZER_FIRE, ANALYZER_VLINES +} AnalyzerMode; + +typedef enum { + ANALYZER_LINES, ANALYZER_BARS +} AnalyzerType; + +typedef enum { + SCOPE_DOT, SCOPE_LINE, SCOPE_SOLID +} ScopeMode; +typedef enum { + VOICEPRINT_NORMAL, VOICEPRINT_FIRE, VOICEPRINT_ICE +} VoiceprintMode; + + +typedef enum { + VU_NORMAL, VU_SMOOTH +} VUMode; + +typedef enum { + REFRESH_FULL, REFRESH_HALF, REFRESH_QUARTER, REFRESH_EIGTH +} RefreshRate; + +typedef enum { + FALLOFF_SLOWEST, FALLOFF_SLOW, FALLOFF_MEDIUM, FALLOFF_FAST, + FALLOFF_FASTEST +} FalloffSpeed; + +typedef struct _UiVis UiVis; +typedef struct _UiVisClass UiVisClass; + +struct _UiVis { + GtkWidget widget; + + gint x, y, width, height; + gfloat data[75], peak[75], peak_speed[75]; + gint refresh_delay; + gboolean scaled; + GtkWidget *fixed; + gboolean visible_window; + GdkWindow *event_window; +}; + +struct _UiVisClass { + GtkWidgetClass parent_class; + void (* doubled) (UiVis *vis); +}; + +GtkWidget* ui_vis_new (GtkWidget *fixed, gint x, gint y, gint width); +GtkType ui_vis_get_type(void); +void ui_vis_set_vis(GtkWidget *widget, gint num); +void ui_vis_clear_data(GtkWidget *widget); +void ui_vis_timeout_func(GtkWidget *widget, guchar * data); +void ui_vis_set_visible(GtkWidget *widget, gboolean window_is_visible); + +#ifdef __cplusplus +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/util.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,1134 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2008 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +/*#define AUD_DEBUG*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "util.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <math.h> + +#include "platform/smartinclude.h" +#include <errno.h> + +#ifdef HAVE_FTS_H +# include <sys/types.h> +# include <sys/stat.h> +# include <fts.h> +#endif + +#include <audacious/input.h> +#include <audacious/playback.h> + +#ifdef USE_CHARDET +# include "../libguess/libguess.h" +# ifdef HAVE_UDET +# include <libudet_c.h> +# endif +#endif + +#include "plugin.h" + +/* + * find <file> in directory <dirname> or subdirectories. return + * pointer to complete filename which has to be freed by calling + * "g_free()" after use. Returns NULL if file could not be found. + */ + +/* somebody tell me how to make use of those funcs from string.h that are in core... */ +gboolean +str_has_suffix_nocase(const gchar * str, const gchar * suffix) +{ + return (strcasecmp(str + strlen(str) - strlen(suffix), suffix) == 0); +} + +static gchar * +str_replace_char(gchar * str, gchar old, gchar new) +{ + gchar *match; + + g_return_val_if_fail(str != NULL, NULL); + + match = str; + while ((match = strchr(match, old))) + *match = new; + + return str; +} + +static gchar * +str_replace_drive_letter(gchar * str) +{ + gchar *match, *match_end; + + g_return_val_if_fail(str != NULL, NULL); + + while ((match = strstr(str, ":\\"))) { + match--; + match_end = match + 3; + *match++ = '/'; + while (*match_end) + *match++ = *match_end++; + *match = 0; /* the end of line */ + } + + return str; +} + +gchar * +convert_dos_path(gchar * path) +{ + g_return_val_if_fail(path != NULL, NULL); + + /* replace drive letter with '/' */ + str_replace_drive_letter(path); + + /* replace '\' with '/' */ + str_replace_char(path, '\\', '/'); + + return path; +} + +gchar * +escape_shell_chars(const gchar * string) +{ + const gchar *special = "$`\"\\"; /* Characters to escape */ + const gchar *in = string; + gchar *out, *escaped; + gint num = 0; + + while (*in != '\0') + if (strchr(special, *in++)) + num++; + + escaped = g_malloc(strlen(string) + num + 1); + + in = string; + out = escaped; + + while (*in != '\0') { + if (strchr(special, *in)) + *out++ = '\\'; + *out++ = *in++; + } + *out = '\0'; + + return escaped; +} + + +typedef struct { + const gchar *to_match; + gchar *match; + gboolean found; +} FindFileContext; + +static const struct { + AFormat afmt; + SAD_sample_format sadfmt; +} format_table[] = { + {FMT_U8, SAD_SAMPLE_U8}, + {FMT_S8, SAD_SAMPLE_S8}, + + {FMT_S16_LE, SAD_SAMPLE_S16_LE}, + {FMT_S16_BE, SAD_SAMPLE_S16_BE}, + {FMT_S16_NE, SAD_SAMPLE_S16}, + + {FMT_U16_LE, SAD_SAMPLE_U16_LE}, + {FMT_U16_BE, SAD_SAMPLE_U16_BE}, + {FMT_U16_NE, SAD_SAMPLE_U16}, + + {FMT_S24_LE, SAD_SAMPLE_S24_LE}, + {FMT_S24_BE, SAD_SAMPLE_S24_BE}, + {FMT_S24_NE, SAD_SAMPLE_S24}, + + {FMT_U24_LE, SAD_SAMPLE_U24_LE}, + {FMT_U24_BE, SAD_SAMPLE_U24_BE}, + {FMT_U24_NE, SAD_SAMPLE_U24}, + + {FMT_S32_LE, SAD_SAMPLE_S32_LE}, + {FMT_S32_BE, SAD_SAMPLE_S32_BE}, + {FMT_S32_NE, SAD_SAMPLE_S32}, + + {FMT_U32_LE, SAD_SAMPLE_U32_LE}, + {FMT_U32_BE, SAD_SAMPLE_U32_BE}, + {FMT_U32_NE, SAD_SAMPLE_U32}, + + {FMT_FLOAT, SAD_SAMPLE_FLOAT}, + {FMT_FIXED32, SAD_SAMPLE_FIXED32}, +}; + +SAD_sample_format +sadfmt_from_afmt(AFormat fmt) +{ + int i; + for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) { + if (format_table[i].afmt == fmt) return format_table[i].sadfmt; + } + + return -1; +} + + +static gboolean +find_file_func(const gchar * path, const gchar * basename, gpointer data) +{ + FindFileContext *context = data; + + if (strlen(path) > FILENAME_MAX) { + AUDDBG("Ignoring path: name too long (%s)\n", path); + return TRUE; + } + + if (aud_vfs_file_test(path, G_FILE_TEST_IS_REGULAR)) { + if (!strcasecmp(basename, context->to_match)) { + context->match = g_strdup(path); + context->found = TRUE; + return TRUE; + } + } + else if (aud_vfs_file_test(path, G_FILE_TEST_IS_DIR)) { + dir_foreach(path, find_file_func, context, NULL); + if (context->found) + return TRUE; + } + + return FALSE; +} + +gchar * +find_file_recursively(const gchar * path, const gchar * filename) +{ + FindFileContext context; + gchar *out = NULL; + + context.to_match = filename; + context.match = NULL; + context.found = FALSE; + + dir_foreach(path, find_file_func, &context, NULL); + + if (context.match) + { + out = g_filename_to_uri(context.match, NULL, NULL); + g_free(context.match); + } + + return out; +} + +gchar * +find_path_recursively(const gchar * path, const gchar * filename) +{ + FindFileContext context; + + context.to_match = filename; + context.match = NULL; + context.found = FALSE; + + dir_foreach(path, find_file_func, &context, NULL); + + return context.match; +} + + +typedef enum { + ARCHIVE_UNKNOWN = 0, + ARCHIVE_DIR, + ARCHIVE_TAR, + ARCHIVE_TGZ, + ARCHIVE_ZIP, + ARCHIVE_TBZ2 +} ArchiveType; + +typedef gchar *(*ArchiveExtractFunc) (const gchar *, const gchar *); + +typedef struct { + ArchiveType type; + const gchar *ext; +} ArchiveExtensionType; + +static ArchiveExtensionType archive_extensions[] = { + {ARCHIVE_TAR, ".tar"}, + {ARCHIVE_ZIP, ".wsz"}, + {ARCHIVE_ZIP, ".zip"}, + {ARCHIVE_TGZ, ".tar.gz"}, + {ARCHIVE_TGZ, ".tgz"}, + {ARCHIVE_TBZ2, ".tar.bz2"}, + {ARCHIVE_TBZ2, ".bz2"}, + {ARCHIVE_UNKNOWN, NULL} +}; + +static gchar *archive_extract_tar(const gchar * archive, const gchar * dest); +static gchar *archive_extract_zip(const gchar * archive, const gchar * dest); +static gchar *archive_extract_tgz(const gchar * archive, const gchar * dest); +static gchar *archive_extract_tbz2(const gchar * archive, const gchar * dest); + +static ArchiveExtractFunc archive_extract_funcs[] = { + NULL, + NULL, + archive_extract_tar, + archive_extract_tgz, + archive_extract_zip, + archive_extract_tbz2 +}; + + +/* FIXME: these functions can be generalised into a function using a + * command lookup table */ + +static const gchar * +get_tar_command(void) +{ + static const gchar *command = NULL; + + if (!command) { + if (!(command = getenv("TARCMD"))) + command = "tar"; + } + + return command; +} + +static const gchar * +get_unzip_command(void) +{ + static const gchar *command = NULL; + + if (!command) { + if (!(command = getenv("UNZIPCMD"))) + command = "unzip"; + } + + return command; +} + + +static gchar * +archive_extract_tar(const gchar * archive, const gchar * dest) +{ + return g_strdup_printf("%s >/dev/null xf \"%s\" -C %s", + get_tar_command(), archive, dest); +} + +static gchar * +archive_extract_zip(const gchar * archive, const gchar * dest) +{ + return g_strdup_printf("%s >/dev/null -o -j \"%s\" -d %s", + get_unzip_command(), archive, dest); +} + +static gchar * +archive_extract_tgz(const gchar * archive, const gchar * dest) +{ + return g_strdup_printf("%s >/dev/null xzf \"%s\" -C %s", + get_tar_command(), archive, dest); +} + +static gchar * +archive_extract_tbz2(const gchar * archive, const gchar * dest) +{ + return g_strdup_printf("bzip2 -dc \"%s\" | %s >/dev/null xf - -C %s", + archive, get_tar_command(), dest); +} + + +ArchiveType +archive_get_type(const gchar * filename) +{ + gint i = 0; + + if (g_file_test(filename, G_FILE_TEST_IS_DIR)) + return ARCHIVE_DIR; + + while (archive_extensions[i].ext) { + if (g_str_has_suffix(filename, archive_extensions[i].ext)) { + return archive_extensions[i].type; + } + i++; + } + + return ARCHIVE_UNKNOWN; +} + +gboolean +file_is_archive(const gchar * filename) +{ + return (archive_get_type(filename) > ARCHIVE_DIR); +} + +gchar * +archive_basename(const gchar * str) +{ + gint i = 0; + + while (archive_extensions[i].ext) { + if (str_has_suffix_nocase(str, archive_extensions[i].ext)) { + const gchar *end = g_strrstr(str, archive_extensions[i].ext); + if (end) { + return g_strndup(str, end - str); + } + break; + } + i++; + } + + return NULL; +} + +/* + decompress_archive + + Decompresses the archive "filename" to a temporary directory, + returns the path to the temp dir, or NULL if failed, + watch out tho, doesn't actually check if the system command succeeds :-| +*/ + +gchar * +archive_decompress(const gchar * filename) +{ + gchar *tmpdir, *cmd, *escaped_filename; + ArchiveType type; +#ifndef HAVE_MKDTEMP + mode_t mode755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; +#endif + + if ((type = archive_get_type(filename)) <= ARCHIVE_DIR) + return NULL; + +#ifdef HAVE_MKDTEMP + tmpdir = g_build_filename(g_get_tmp_dir(), "audacious.XXXXXXXX", NULL); + if (!mkdtemp(tmpdir)) { + g_free(tmpdir); + AUDDBG("Unable to load skin: Failed to create temporary " + "directory: %s\n", g_strerror(errno)); + return NULL; + } +#else + tmpdir = g_strdup_printf("%s/audacious.%ld", g_get_tmp_dir(), (long) rand()); + make_directory(tmpdir, mode755); +#endif + + escaped_filename = escape_shell_chars(filename); + cmd = archive_extract_funcs[type] (escaped_filename, tmpdir); + g_free(escaped_filename); + + if (!cmd) { + AUDDBG("extraction function is NULL!\n"); + g_free(tmpdir); + return NULL; + } + + AUDDBG("Attempt to execute \"%s\"\n", cmd); + + if(system(cmd) != 0) + { + AUDDBG("could not execute cmd %s\n",cmd); + g_free(cmd); + return NULL; + } + g_free(cmd); + + return tmpdir; +} + + +#ifdef HAVE_FTS_H + +void +del_directory(const gchar * dirname) +{ + gchar *const argv[2] = { (gchar *) dirname, NULL }; + FTS *fts; + FTSENT *p; + + fts = fts_open(argv, FTS_PHYSICAL, (gint(*)())NULL); + while ((p = fts_read(fts))) { + switch (p->fts_info) { + case FTS_D: + break; + case FTS_DNR: + case FTS_ERR: + break; + case FTS_DP: + rmdir(p->fts_accpath); + break; + default: + unlink(p->fts_accpath); + break; + } + } + fts_close(fts); +} + +#else /* !HAVE_FTS */ + +gboolean +del_directory_func(const gchar * path, const gchar * basename, + gpointer params) +{ + if (!strcmp(basename, ".") || !strcmp(path, "..")) + return FALSE; + + if (g_file_test(path, G_FILE_TEST_IS_DIR)) { + dir_foreach(path, del_directory_func, NULL, NULL); + rmdir(path); + return FALSE; + } + + unlink(path); + + return FALSE; +} + +void +del_directory(const gchar * path) +{ + dir_foreach(path, del_directory_func, NULL, NULL); + rmdir(path); +} + +#endif /* ifdef HAVE_FTS */ + +static void +strip_string(GString *string) +{ + while (string->len > 0 && string->str[0] == ' ') + g_string_erase(string, 0, 1); + + while (string->len > 0 && string->str[string->len - 1] == ' ') + g_string_erase(string, string->len - 1, 1); +} + +static void +strip_lower_string(GString *string) +{ + gchar *lower; + strip_string(string); + + lower = g_ascii_strdown(string->str, -1); + g_free(string->str); + string->str = lower; +} + +static void +close_ini_file_free_value(gpointer value) +{ + g_free((gchar*)value); +} + +static void +close_ini_file_free_section(gpointer section) +{ + g_hash_table_destroy((GHashTable*)section); +} + +INIFile * +open_ini_file(const gchar *filename) +{ + GHashTable *ini_file = NULL; + GHashTable *section = NULL; + GString *section_name, *key_name, *value; + gpointer section_hash, key_hash; + gchar *buffer = NULL; + gsize off = 0; + gsize filesize = 0; + + unsigned char x[] = { 0xff, 0xfe, 0x00 }; + + g_return_val_if_fail(filename, NULL); + aud_vfs_file_get_contents(filename, &buffer, &filesize); + if (buffer == NULL) + return NULL; + + /* + * Convert UTF-16 into something useful. Original implementation + * by incomp@#audacious. Cleanups \nenolod + * FIXME: can't we use a GLib function for that? -- 01mf02 + */ + if (filesize > 2 && !memcmp(&buffer[0],&x,2)) + { + gchar *outbuf = g_malloc (filesize); /* it's safe to waste memory. */ + guint counter; + + for (counter = 2; counter < filesize; counter += 2) + { + if (!memcmp(&buffer[counter+1], &x[2], 1)) { + outbuf[(counter-2)/2] = buffer[counter]; + } else { + g_free(buffer); + g_free(outbuf); + return NULL; + } + } + + outbuf[(counter-2)/2] = '\0'; + + if ((filesize - 2) / 2 == (counter - 2) / 2) + { + g_free(buffer); + buffer = outbuf; + } + else + { + g_free(buffer); + g_free(outbuf); + return NULL; /* XXX wrong encoding */ + } + } + + section_name = g_string_new(""); + key_name = g_string_new(NULL); + value = g_string_new(NULL); + + ini_file = g_hash_table_new_full(NULL, NULL, NULL, + close_ini_file_free_section); + section = g_hash_table_new_full(NULL, NULL, NULL, + close_ini_file_free_value); + /* make a nameless section which should store all entries that are not + * embedded in a section */ + section_hash = GINT_TO_POINTER(g_string_hash(section_name)); + g_hash_table_insert(ini_file, section_hash, section); + + while (off < filesize) + { + /* ignore the following characters */ + if (buffer[off] == '\r' || buffer[off] == '\n' || + buffer[off] == ' ' || buffer[off] == '\t') + { + if (buffer[off] == '\n') + { + g_string_free(key_name, TRUE); + g_string_free(value, TRUE); + key_name = g_string_new(NULL); + value = g_string_new(NULL); + } + + off++; + continue; + } + + /* if we encounter a possible section statement */ + if (buffer[off] == '[') + { + g_string_free(section_name, TRUE); + section_name = g_string_new(NULL); + off++; + + if (off >= filesize) + goto return_sequence; + + while (buffer[off] != ']') + { + /* if the section statement has not been closed before a + * linebreak */ + if (buffer[off] == '\n') + break; + + g_string_append_c(section_name, buffer[off]); + off++; + if (off >= filesize) + goto return_sequence; + } + if (buffer[off] == '\n') + continue; + if (buffer[off] == ']') + { + off++; + if (off >= filesize) + goto return_sequence; + + strip_lower_string(section_name); + section_hash = GINT_TO_POINTER(g_string_hash(section_name)); + + /* if this section already exists, we don't make a new one, + * but reuse the old one */ + if (g_hash_table_lookup(ini_file, section_hash) != NULL) + section = g_hash_table_lookup(ini_file, section_hash); + else + { + section = g_hash_table_new_full(NULL, NULL, NULL, + close_ini_file_free_value); + g_hash_table_insert(ini_file, section_hash, section); + } + + continue; + } + } + + if (buffer[off] == '=') + { + off++; + if (off >= filesize) + goto return_sequence; + + while (buffer[off] != '\n' && buffer[off] != '\r') + { + g_string_append_c(value, buffer[off]); + off++; + if (off >= filesize) + break; + } + + strip_lower_string(key_name); + key_hash = GINT_TO_POINTER(g_string_hash(key_name)); + strip_string(value); + + if (key_name->len > 0 && value->len > 0) + g_hash_table_insert(section, key_hash, g_strdup(value->str)); + } + else + { + g_string_append_c(key_name, buffer[off]); + off++; + if (off >= filesize) + goto return_sequence; + } + } + +return_sequence: + g_string_free(section_name, TRUE); + g_string_free(key_name, TRUE); + g_string_free(value, TRUE); + g_free(buffer); + return ini_file; +} + +/** + * Frees the memory allocated for inifile. + */ +void +close_ini_file(INIFile *inifile) +{ + g_return_if_fail(inifile); + g_hash_table_destroy(inifile); +} + +/** + * Returns a string that corresponds to correct section and key in inifile. + * + * Returns NULL if value was not found in inifile. Otherwise returns a copy + * of string pointed by "section" and "key". Returned string should be freed + * after use. + */ +gchar * +read_ini_string(INIFile *inifile, const gchar *section, const gchar *key) +{ + GString *section_string; + GString *key_string; + gchar *value = NULL; + gpointer section_hash, key_hash; + GHashTable *section_table; + + g_return_val_if_fail(inifile, NULL); + + section_string = g_string_new(section); + key_string = g_string_new(key); + value = NULL; + + strip_lower_string(section_string); + strip_lower_string(key_string); + section_hash = GINT_TO_POINTER(g_string_hash(section_string)); + key_hash = GINT_TO_POINTER(g_string_hash(key_string)); + section_table = g_hash_table_lookup(inifile, section_hash); + + if (section_table) { + value = g_strdup(g_hash_table_lookup(section_table, + GINT_TO_POINTER(key_hash))); + } + + g_string_free(section_string, TRUE); + g_string_free(key_string, TRUE); + + g_return_val_if_fail(value, NULL); + return value; +} + +GArray * +read_ini_array(INIFile *inifile, const gchar *section, const gchar *key) +{ + gchar *temp; + GArray *a; + + g_return_val_if_fail((temp = read_ini_string(inifile, section, key)), NULL); + + a = string_to_garray(temp); + g_free(temp); + return a; +} + +GArray * +string_to_garray(const gchar * str) +{ + GArray *array; + gint temp; + const gchar *ptr = str; + gchar *endptr; + + array = g_array_new(FALSE, TRUE, sizeof(gint)); + for (;;) { + temp = strtol(ptr, &endptr, 10); + if (ptr == endptr) + break; + g_array_append_val(array, temp); + ptr = endptr; + while (!isdigit((int) *ptr) && (*ptr) != '\0') + ptr++; + if (*ptr == '\0') + break; + } + return (array); +} + +void +glist_movedown(GList * list) +{ + gpointer temp; + + if (g_list_next(list)) { + temp = list->data; + list->data = list->next->data; + list->next->data = temp; + } +} + +void +glist_moveup(GList * list) +{ + gpointer temp; + + if (g_list_previous(list)) { + temp = list->data; + list->data = list->prev->data; + list->prev->data = temp; + } +} + +GdkFont * +util_font_load(const gchar * name) +{ + GdkFont *font; + PangoFontDescription *desc; + + desc = pango_font_description_from_string(name); + font = gdk_font_from_description(desc); + + return font; +} + +/* text_get_extents() taken from The GIMP (C) Spencer Kimball, Peter + * Mattis et al */ +gboolean +text_get_extents(const gchar * fontname, + const gchar * text, + gint * width, gint * height, gint * ascent, gint * descent) +{ + PangoFontDescription *font_desc; + PangoLayout *layout; + PangoRectangle rect; + + g_return_val_if_fail(fontname != NULL, FALSE); + g_return_val_if_fail(text != NULL, FALSE); + + /* FIXME: resolution */ + layout = gtk_widget_create_pango_layout(GTK_WIDGET(mainwin), text); + + font_desc = pango_font_description_from_string(fontname); + pango_layout_set_font_description(layout, font_desc); + pango_font_description_free(font_desc); + pango_layout_get_pixel_extents(layout, NULL, &rect); + + if (width) + *width = rect.width; + if (height) + *height = rect.height; + + if (ascent || descent) { + PangoLayoutIter *iter; + PangoLayoutLine *line; + + iter = pango_layout_get_iter(layout); + line = pango_layout_iter_get_line(iter); + pango_layout_iter_free(iter); + + pango_layout_line_get_pixel_extents(line, NULL, &rect); + + if (ascent) + *ascent = PANGO_ASCENT(rect); + if (descent) + *descent = -PANGO_DESCENT(rect); + } + + g_object_unref(layout); + + return TRUE; +} + +/* counts number of digits in a gint */ +guint +gint_count_digits(gint n) +{ + guint count = 0; + + n = ABS(n); + do { + count++; + n /= 10; + } while (n > 0); + + return count; +} + +gboolean +dir_foreach(const gchar * path, DirForeachFunc function, + gpointer user_data, GError ** error) +{ + GError *error_out = NULL; + GDir *dir; + const gchar *entry; + gchar *entry_fullpath; + + if (!(dir = g_dir_open(path, 0, &error_out))) { + g_propagate_error(error, error_out); + return FALSE; + } + + while ((entry = g_dir_read_name(dir))) { + entry_fullpath = g_build_filename(path, entry, NULL); + + if ((*function) (entry_fullpath, entry, user_data)) { + g_free(entry_fullpath); + break; + } + + g_free(entry_fullpath); + } + + g_dir_close(dir); + + return TRUE; +} + +GtkWidget * +make_filebrowser(const gchar *title, gboolean save) +{ + GtkWidget *dialog; + GtkWidget *button; + + g_return_val_if_fail(title != NULL, NULL); + + dialog = gtk_file_chooser_dialog_new(title, GTK_WINDOW(mainwin), + save ? + GTK_FILE_CHOOSER_ACTION_SAVE : + GTK_FILE_CHOOSER_ACTION_OPEN, + NULL, NULL); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT); + + gtk_button_set_use_stock(GTK_BUTTON(button), TRUE); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), save ? + GTK_STOCK_SAVE : GTK_STOCK_OPEN, + GTK_RESPONSE_ACCEPT); + + gtk_button_set_use_stock(GTK_BUTTON(button), TRUE); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + + return dialog; +} + +/** + * util_info_dialog: + * @title: The title of the message to show. + * @text: The text of the message to show. + * @button_text: The text of the button which will close the messagebox. + * @modal: Whether or not the messagebox should be modal. + * @button_action: Code to execute on when the messagebox is closed, or %NULL. + * @action_data: Optional opaque data to pass to @button_action. + * + * Displays a message box. + * + * Return value: A GTK widget handle for the message box. + **/ +GtkWidget * +util_info_dialog(const gchar * title, const gchar * text, + const gchar * button_text, gboolean modal, + GCallback button_action, gpointer action_data) +{ + GtkWidget *dialog; + GtkWidget *dialog_vbox, *dialog_hbox, *dialog_bbox; + GtkWidget *dialog_bbox_b1; + GtkWidget *dialog_textlabel; + GtkWidget *dialog_icon; + + dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint( GTK_WINDOW(dialog) , GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_modal( GTK_WINDOW(dialog) , modal ); + gtk_window_set_title( GTK_WINDOW(dialog) , title ); + gtk_container_set_border_width( GTK_CONTAINER(dialog) , 10 ); + + dialog_vbox = gtk_vbox_new( FALSE , 0 ); + dialog_hbox = gtk_hbox_new( FALSE , 0 ); + + /* icon */ + dialog_icon = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_DIALOG ); + gtk_box_pack_start( GTK_BOX(dialog_hbox) , dialog_icon , FALSE , FALSE , 2 ); + + /* label */ + dialog_textlabel = gtk_label_new( text ); + /* gtk_label_set_selectable( GTK_LABEL(dialog_textlabel) , TRUE ); */ + gtk_box_pack_start( GTK_BOX(dialog_hbox) , dialog_textlabel , TRUE , TRUE , 2 ); + + gtk_box_pack_start( GTK_BOX(dialog_vbox) , dialog_hbox , FALSE , FALSE , 2 ); + gtk_box_pack_start( GTK_BOX(dialog_vbox) , gtk_hseparator_new() , FALSE , FALSE , 4 ); + + dialog_bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(dialog_bbox) , GTK_BUTTONBOX_END ); + dialog_bbox_b1 = gtk_button_new_with_label( button_text ); + g_signal_connect_swapped( G_OBJECT(dialog_bbox_b1) , "clicked" , + G_CALLBACK(gtk_widget_destroy) , dialog ); + if ( button_action ) + g_signal_connect( G_OBJECT(dialog_bbox_b1) , "clicked" , + button_action , action_data ); + + gtk_container_add( GTK_CONTAINER(dialog_bbox) , dialog_bbox_b1 ); + gtk_box_pack_start( GTK_BOX(dialog_vbox) , dialog_bbox , FALSE , FALSE , 0 ); + + gtk_container_add( GTK_CONTAINER(dialog) , dialog_vbox ); + + GTK_WIDGET_SET_FLAGS( dialog_bbox_b1 , GTK_CAN_DEFAULT); + gtk_widget_grab_default( dialog_bbox_b1 ); + + gtk_widget_show_all(dialog); + + return dialog; +} + + +/** + * util_get_localdir: + * + * Returns a string with the full path of Audacious local datadir (where config files are placed). + * It's useful in order to put in the right place custom config files for audacious plugins. + * + * Return value: a string with full path of Audacious local datadir (should be freed after use) + **/ +gchar* +util_get_localdir(void) +{ + gchar *datadir; + gchar *tmp; + + if ( (tmp = getenv("XDG_CONFIG_HOME")) == NULL ) + datadir = g_build_filename( g_get_home_dir() , ".config" , "audacious" , NULL ); + else + datadir = g_build_filename( tmp , "audacious" , NULL ); + + return datadir; +} + + +gchar * +construct_uri(gchar *string, const gchar *playlist_name) // uri, path and anything else +{ + gchar *filename = g_strdup(string); + gchar *tmp, *path; + gchar *uri = NULL; + + /* try to translate dos path */ + convert_dos_path(filename); /* in place replacement */ + + // make full path uri here + // case 1: filename is raw full path or uri + if (filename[0] == '/' || strstr(filename, "://")) { + uri = g_filename_to_uri(filename, NULL, NULL); + if(!uri) { + uri = g_strdup(filename); + } + g_free(filename); + } + // case 2: filename is not raw full path nor uri, playlist path is full path + // make full path by replacing last part of playlist path with filename. (using g_build_filename) + else if (playlist_name[0] == '/' || strstr(playlist_name, "://")) { + path = g_filename_from_uri(playlist_name, NULL, NULL); + if (!path) { + path = g_strdup(playlist_name); + } + tmp = strrchr(path, '/'); *tmp = '\0'; + tmp = g_build_filename(path, filename, NULL); + g_free(path); g_free(filename); + uri = g_filename_to_uri(tmp, NULL, NULL); + g_free(tmp); + } + // case 3: filename is not raw full path nor uri, playlist path is not full path + // just abort. + else { + g_free(filename); + return NULL; + } + + AUDDBG("uri=%s\n", uri); + return uri; +} + +/* + * minimize number of realloc's: + * - set N to nearest power of 2 not less then N + * - double it + * + * -- asphyx + * + * XXX: what's so smart about this?? seems wasteful and silly. --nenolod + */ +gpointer +smart_realloc(gpointer ptr, gsize *size) +{ + *size = (size_t)pow(2, ceil(log(*size) / log(2)) + 1); + if (ptr != NULL) free(ptr); + ptr = malloc(*size); + return ptr; +} + +void +make_directory(const gchar * path, mode_t mode) +{ + if (g_mkdir_with_parents(path, mode) == 0) + return; + + g_printerr(_("Could not create directory (%s): %s\n"), path, + g_strerror(errno)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/skins/util.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,103 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2008 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef UTIL_H +#define UTIL_H + +#ifdef _AUDACIOUS_CORE +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include <glib.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#include "audacious/plugin.h" +#include "libSAD/libSAD.h" + +#define SWAP(a, b) { a^=b; b^=a; a^=b; } + +typedef gboolean(*DirForeachFunc) (const gchar * path, + const gchar * basename, + gpointer user_data); + + +gchar *find_file_recursively(const gchar * dirname, const gchar * file); +gchar *find_path_recursively(const gchar * dirname, const gchar * file); +void del_directory(const gchar * dirname); +gboolean dir_foreach(const gchar * path, DirForeachFunc function, + gpointer user_data, GError ** error); + + +INIFile *open_ini_file(const gchar *filename); +void close_ini_file(INIFile *key_file); +gchar *read_ini_string(INIFile *key_file, const gchar *section, + const gchar *key); +GArray *read_ini_array(INIFile *key_file, const gchar *section, + const gchar *key); + +GArray *string_to_garray(const gchar * str); + +void glist_movedown(GList * list); +void glist_moveup(GList * list); + +GdkFont *util_font_load(const gchar * name); +void util_set_cursor(GtkWidget * window); +gboolean text_get_extents(const gchar * fontname, const gchar * text, + gint * width, gint * height, gint * ascent, + gint * descent); + +gboolean file_is_archive(const gchar * filename); +gchar *archive_decompress(const gchar * path); +gchar *archive_basename(const gchar * path); + +guint gint_count_digits(gint n); + + +GtkWidget *make_filebrowser(const gchar *title, gboolean save); + +GtkWidget *util_info_dialog(const gchar * title, const gchar * text, + const gchar * button_text, gboolean modal, GCallback button_action, + gpointer action_data); + +GdkPixbuf *audacious_create_colorized_pixbuf(GdkPixbuf *src, gint red, gint green, gint blue); + +gchar *util_get_localdir(void); + +gchar *construct_uri(gchar *string, const gchar *playlist_name); + +SAD_sample_format sadfmt_from_afmt(AFormat fmt); + +/* minimizes number of realloc's */ +gpointer smart_realloc(gpointer ptr, gsize *size); + +void make_directory(const gchar * path, mode_t mode); + +G_END_DECLS + +#endif
--- a/src/sndfile/plugin.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sndfile/plugin.c Thu May 22 19:32:39 2008 +0200 @@ -35,7 +35,6 @@ #include <math.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/i18n.h> #include <audacious/output.h> #include "plugin.h"
--- a/src/spectrum/spectrum.c Thu May 22 19:31:48 2008 +0200 +++ b/src/spectrum/spectrum.c Thu May 22 19:32:39 2008 +0200 @@ -24,7 +24,6 @@ #include <gtk/gtk.h> #include <math.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/i18n.h> #include "logo.xpm"
--- a/src/statusicon/si_ui.c Thu May 22 19:31:48 2008 +0200 +++ b/src/statusicon/si_ui.c Thu May 22 19:32:39 2008 +0200 @@ -24,7 +24,7 @@ #include "si_common.h" #include "gtktrayicon.h" #include <audacious/ui_fileinfopopup.h> -#include <audacious/util.h> +#include <audacious/plugin.h> #include <audacious/i18n.h> #include <glib.h> #include <gdk/gdk.h>
--- a/src/stdio/stdio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/stdio/stdio.c Thu May 22 19:32:39 2008 +0200 @@ -18,7 +18,6 @@ #include "config.h" #include <audacious/plugin.h> -#include <audacious/strings.h> #include <stdio.h> #include <unistd.h>
--- a/src/stereo_plugin/stereo.c Thu May 22 19:31:48 2008 +0200 +++ b/src/stereo_plugin/stereo.c Thu May 22 19:32:39 2008 +0200 @@ -1,7 +1,6 @@ #include "config.h" #include <gtk/gtk.h> #include <audacious/i18n.h> -#include <audacious/util.h> #include <audacious/plugin.h> @@ -9,6 +8,7 @@ static void about(void); static void configure(void); static int mod_samples(gpointer *d, gint length, AFormat afmt, gint srate, gint nch); +static void query_format(AFormat * fmt, gint * rate, gint * nch); @@ -18,7 +18,8 @@ .init = init, .about = about, .configure = configure, - .mod_samples = mod_samples + .mod_samples = mod_samples, + .query_format = query_format }; static const char *about_text = N_("Extra Stereo Plugin\n\n" @@ -140,6 +141,17 @@ gtk_widget_show(conf_dialog); } +static void query_format(AFormat * fmt, gint * rate, gint * nch) +{ + if (!(*fmt == FMT_S16_NE || + (*fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) || + (*fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN))) + *fmt = FMT_S16_NE; + + if (*nch != 2) + *nch = 2; +} + static int mod_samples(gpointer *d, gint length, AFormat afmt, gint srate, gint nch) { gint i;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/Makefile Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,14 @@ +PLUGIN = streambrowser${PLUGIN_SUFFIX} + +SRCS = streambrowser.c \ + streamdir.c \ + shoutcast.c + +include ../../buildsys.mk +include ../../extra.mk + +plugindir := ${plugindir}/${INPUT_PLUGIN_DIR} + +CFLAGS += ${PLUGIN_CFLAGS} +CPPFLAGS += ${PLUGIN_CPPFLAGS} ${MOWGLI_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${XML_CPPFLAGS} ${ARCH_DEFINES} -I../.. +LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${MOWGLI_LIBS} ${XML_LIBS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/shoutcast.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,101 @@ + +#include <string.h> +#include <glib.h> +#include <libxml/parser.h> +#include <libxml/tree.h> + +#include "streambrowser.h" +#include "shoutcast.h" + + +static streaminfo_t* shoutcast_streaminfo_fetch(gchar *station_name, gchar *station_id); +static category_t* shoutcast_category_fetch(gchar *category_name); + + +static streaminfo_t *shoutcast_streaminfo_fetch(gchar *station_name, gchar *station_id) +{ + gchar url[DEF_STRING_LEN]; + g_snprintf(url, DEF_STRING_LEN, SHOUTCAST_STREAMINFO_URL, station_id); + + streaminfo_t *streaminfo = streaminfo_new(station_name, url); + + // todo: read the .pls file fetched from the above url + + return streaminfo; +} + +static category_t *shoutcast_category_fetch(gchar *category_name) +{ + category_t *category = category_new(category_name); + + gchar url[DEF_STRING_LEN]; + g_snprintf(url, DEF_STRING_LEN, SHOUTCAST_CATEGORY_URL, category_name); + + xmlDoc *doc = xmlReadFile(url, NULL, 0); + if (doc == NULL) { + error(" shoutcast: failed to read \"%s\" category file\n", category_name); + return NULL; + } + + debug(" shoutcast: category file fetched\n"); + + xmlNode *root_node = xmlDocGetRootElement(doc); + xmlNode *node; + + root_node = root_node->children; + + for (node = root_node; node != NULL; node = node->next) { + if (node->type == XML_ELEMENT_NODE && !strcmp((char *) node->name, "station")) { + gchar *station_name = (gchar*) xmlGetProp(node, (xmlChar *) "name"); + gchar *station_id = (gchar*) xmlGetProp(node, (xmlChar *) "id"); + + debug(" shoutcast: fetching stream info for name = \"%s\" and id = %s\n", station_name, station_id); + + streaminfo_t *streaminfo = shoutcast_streaminfo_fetch(station_name, station_id); + streaminfo_add(category, streaminfo); + + // todo: debug - print info about streaminfon urls + debug(" shoutcast: stream info added for name = \"%s\" and id = %s\n", station_name, station_id); + } + } + + return category; +} + + +streamdir_t* shoutcast_streamdir_fetch() +{ + streamdir_t *streamdir = streamdir_new("Shoutcast"); + + debug("shoutcast: fetching streaming directory file\n"); + + // todo: replace dummy filename with SHOUTCAST_DIRECTORY_URL + xmlDoc *doc = xmlReadFile("shoutcast.xml", NULL, 0); + if (doc == NULL) { + error("shoutcast: failed to read stream directory file\n"); + return NULL; + } + + debug("shoutcast: streaming directory file fetched\n"); + + xmlNode *root_node = xmlDocGetRootElement(doc); + xmlNode *node; + + root_node = root_node->children; + + for (node = root_node; node != NULL; node = node->next) { + if (node->type == XML_ELEMENT_NODE) { + gchar *category_name = (gchar*) xmlGetProp(node, (xmlChar *) "name"); + + debug(" shoutcast: fetching category \"%s\"\n", category_name); + + category_t *category = shoutcast_category_fetch(category_name); + category_add(streamdir, category); + + debug(" shoutcast: added category \"%s\"\n", category_name); + } + } + + exit(0); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/shoutcast.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,17 @@ + +#ifndef SHOUTCAST_H +#define SHOUTCAST_H + +#include "streambrowser.h" +#include "streamdir.h" + +#define SHOUTCAST_STREAMDIR_URL "http://www.shoutcast.com/sbin/newxml.phtml" +#define SHOUTCAST_CATEGORY_URL "http://www.shoutcast.com/sbin/newxml.phtml?genre=%s" +#define SHOUTCAST_STREAMINFO_URL "http://www.shoutcast.com/sbin/shoutcast-playlist.pls?rn=%s&file=filename.pls" + + +streamdir_t* shoutcast_streamdir_fetch(); + + +#endif // SHOUTCAST_H +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/shoutcast.xml Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding='UTF-8' standalone="yes"?> +<genrelist> +<genre name="24h"></genre> +<genre name="Acid"></genre> +<genre name="Adult"></genre> +<genre name="Adulto"></genre> +<genre name="African"></genre> +<genre name="Afrikaans"></genre> +<genre name="Afro"></genre> +<genre name="Zouk"></genre> +</genrelist> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streambrowser.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,100 @@ + +#include <stdlib.h> +#include <gtk/gtk.h> +#include <audacious/plugin.h> +#include <audacious/ui_plugin_menu.h> + +#include "streambrowser.h" +#include "streamdir.h" +#include "shoutcast.h" + + +static void sb_init(); +static void sb_about(); +static void sb_configure(); +static void sb_cleanup(); + +static void menu_click(); +static void add_plugin_services_menu_item(); + + +static GeneralPlugin sb_plugin = +{ + .description = "Stream Browser", + .init = sb_init, + .about = sb_about, + .configure = sb_configure, + .cleanup = sb_cleanup +}; + +GeneralPlugin *sb_gplist[] = +{ + &sb_plugin, + NULL +}; + +SIMPLE_GENERAL_PLUGIN(streambrowser, sb_gplist); + + +void debug(const char *fmt, ...) +{ + // todo: replace with config->debug + if (TRUE) { + va_list ap; + fprintf(stderr, "* streambrowser: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +void error(const char *fmt, ...) +{ + va_list ap; + fprintf(stderr, "! streambrowser: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +static void sb_init() +{ + debug("sb_init()\n"); + + //shoutcast_streamdir_fetch(); +} + +static void sb_about() +{ + debug("sb_about()\n"); +} + +static void sb_configure() +{ + debug("sb_configure()\n"); +} + +static void sb_cleanup() +{ + debug("sb_cleanup()\n"); +} + +static void menu_click() +{ + debug("menu_click()\n"); +} + +static void add_plugin_services_menu_item() +{ + /* + GtkWidget *menu_item; + + menu_item = gtk_image_menu_item_new_with_label("SB Test"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_CDROM, GTK_ICON_SIZE_MENU)); + gtk_widget_show(menu_item); + audacious_menu_plugin_item_add(AUDACIOUS_MENU_PLAYLIST_RCLICK, menu_item); + g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(menu_click), NULL); + */ +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streambrowser.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,13 @@ + +#ifndef STREAMBROWSER_H +#define STREAMBROWSER_H + +#define DEF_STRING_LEN 256 + + +void debug(const char *fmt, ...); +void error(const char *fmt, ...); + + +#endif // STREAMBROWSER_H +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streamdir.c Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,138 @@ + +#include <string.h> +#include <glib.h> + +#include "streambrowser.h" +#include "streamdir.h" + + +streamdir_t* streamdir_new(gchar *name) +{ + streamdir_t *streamdir = (streamdir_t*) g_malloc(sizeof(streamdir_t)); + strncpy(streamdir->name, name, DEF_STRING_LEN); + streamdir->category_list = NULL; + + return streamdir; +} + +void streamdir_delete(streamdir_t *streamdir) +{ + GList *iterator; + category_t *category; + + for (iterator = g_list_first(streamdir->category_list); iterator != NULL; iterator = g_list_next(streamdir->category_list)) { + category = iterator->data; + category_delete(category); + } + + g_list_free(streamdir->category_list); + g_free(streamdir); +} + + +category_t* category_new(gchar *name) +{ + category_t *category = (category_t*) g_malloc(sizeof(category_t)); + strncpy(category->name, name, DEF_STRING_LEN); + category->streaminfo_list = NULL; + + return category; +} + +void category_delete(category_t *category) +{ + GList *iterator; + streaminfo_t *streaminfo; + + for (iterator = g_list_first(category->streaminfo_list); iterator != NULL; iterator = g_list_next(category->streaminfo_list)) { + streaminfo = iterator->data; + streaminfo_delete(streaminfo); + } + + g_list_free(category->streaminfo_list); + g_free(category); +} + +void category_add(streamdir_t *streamdir, category_t *category) +{ + streamdir->category_list = g_list_append(streamdir->category_list, category); +} + +void category_remove(streamdir_t *streamdir, category_t *category) +{ + streamdir->category_list = g_list_remove(streamdir->category_list, category); +} + +category_t* category_get_by_index(streamdir_t *streamdir, gint index) +{ + return (category_t*) g_list_nth_data(streamdir->category_list, index); +} + +category_t* category_get_by_name(streamdir_t *streamdir, gchar *name) +{ + GList *iterator; + category_t *category; + + for (iterator = g_list_first(streamdir->category_list); iterator != NULL; iterator = g_list_next(streamdir->category_list)) { + category = iterator->data; + if (!strncasecmp(category->name, name, DEF_STRING_LEN)) + return category; + } + + return NULL; +} + +gint category_get_count(streamdir_t *streamdir) +{ + return g_list_length(streamdir->category_list); +} + + +streaminfo_t* streaminfo_new(gchar *name, gchar *url) +{ + streaminfo_t *streaminfo = (streaminfo_t*) g_malloc(sizeof(streaminfo_t)); + strncpy(streaminfo->name, name, DEF_STRING_LEN); + strncpy(streaminfo->url, url, DEF_STRING_LEN); + + return streaminfo; +} + +void streaminfo_delete(streaminfo_t *streaminfo) +{ + g_free(streaminfo); +} + +void streaminfo_add(category_t *category, streaminfo_t *streaminfo) +{ + category->streaminfo_list = g_list_append(category->streaminfo_list, streaminfo); +} + +void streaminfo_remove(category_t *category, streaminfo_t *streaminfo) +{ + category->streaminfo_list = g_list_remove(category->streaminfo_list, streaminfo); +} + +streaminfo_t* streaminfo_get_by_index(category_t *category, gint index) +{ + return (streaminfo_t*) g_list_nth_data(category->streaminfo_list, index); +} + +streaminfo_t* streaminfo_get_by_name(category_t *category, gchar *name) +{ + GList *iterator; + streaminfo_t *streaminfo; + + for (iterator = g_list_first(category->streaminfo_list); iterator != NULL; iterator = g_list_next(category->streaminfo_list)) { + streaminfo = iterator->data; + if (!strncasecmp(streaminfo->name, name, DEF_STRING_LEN)) + return streaminfo; + } + + return NULL; +} + +gint streaminfo_get_count(category_t *category) +{ + return g_list_length(category->streaminfo_list); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streamdir.h Thu May 22 19:32:39 2008 +0200 @@ -0,0 +1,55 @@ + +#ifndef STREAMDIR_H +#define STREAMDIR_H + + +#include <glib.h> + +#include "streambrowser.h" + + +typedef struct { + + gchar name[DEF_STRING_LEN]; + gchar url[DEF_STRING_LEN]; + +} streaminfo_t; + +typedef struct { + + gchar name[DEF_STRING_LEN]; + GList* streaminfo_list; + +} category_t; + +typedef struct { + + gchar name[DEF_STRING_LEN]; + GList* category_list; + +} streamdir_t; + + +streamdir_t* streamdir_new(gchar *name); +void streamdir_delete(streamdir_t *streamdir); + +category_t* category_new(gchar *name); +void category_delete(category_t *category); +void category_add(streamdir_t *streamdir, category_t *category); +void category_remove(streamdir_t *streamdir, category_t *category); +category_t* category_get_by_index(streamdir_t *streamdir, gint index); +category_t* category_get_by_name(streamdir_t *streamdir, gchar *name); +gint category_get_count(streamdir_t *streamdir); + +streaminfo_t* streaminfo_new(gchar *name, gchar *url); +void streaminfo_delete(streaminfo_t *streaminfo); +void streaminfo_free(streaminfo_t *streaminfo); +void streaminfo_add(category_t *category, streaminfo_t *streaminfo); +void streaminfo_remove(category_t *category, streaminfo_t *streaminfo); +streaminfo_t* streaminfo_get_by_index(category_t *category, gint index); +streaminfo_t* streaminfo_get_by_name(category_t *category, gchar *name); +gint streaminfo_get_count(category_t *category); + + +#endif // STREAMDIR_H +
--- a/src/sun/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sun/about.c Thu May 22 19:32:39 2008 +0200 @@ -20,7 +20,6 @@ #include <glib.h> #include "sun.h" -#include <audacious/util.h> #include <audacious/i18n.h> void sun_about(void)
--- a/src/sun/audio.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sun/audio.c Thu May 22 19:32:39 2008 +0200 @@ -20,7 +20,6 @@ /* FIXME: g_error() is used several places, it will exit xmms */ #include <errno.h> -#include <audacious/util.h> #include "sun.h" #include "resample.h"
--- a/src/sun/configure.c Thu May 22 19:31:48 2008 +0200 +++ b/src/sun/configure.c Thu May 22 19:32:39 2008 +0200 @@ -22,7 +22,6 @@ #include <errno.h> #include "sun.h" -#include <audacious/util.h> #include <audacious/i18n.h> #include "mixer.h"
--- a/src/timidity/xmms-timidity.c Thu May 22 19:31:48 2008 +0200 +++ b/src/timidity/xmms-timidity.c Thu May 22 19:32:39 2008 +0200 @@ -19,7 +19,6 @@ #include "config.h" -#include <audacious/util.h> #include <glib.h> #include <gtk/gtk.h> #include <string.h>
--- a/src/tonegen/tonegen.c Thu May 22 19:31:48 2008 +0200 +++ b/src/tonegen/tonegen.c Thu May 22 19:32:39 2008 +0200 @@ -20,7 +20,6 @@ #include "config.h" #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include <audacious/i18n.h> #include <glib.h> #include <stdlib.h>
--- a/src/tta/libtta.c Thu May 22 19:31:48 2008 +0200 +++ b/src/tta/libtta.c Thu May 22 19:32:39 2008 +0200 @@ -42,9 +42,7 @@ #include <string.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/output.h> -#include <audacious/strings.h> #include <audacious/i18n.h> #include <audacious/id3tag.h>
--- a/src/voice_removal/voice_removal.c Thu May 22 19:31:48 2008 +0200 +++ b/src/voice_removal/voice_removal.c Thu May 22 19:32:39 2008 +0200 @@ -28,16 +28,29 @@ static int apply_effect (gpointer *d, gint length, AFormat afmt, gint srate, gint nch); +static void query_format (AFormat *fmt, gint *rate, gint *nch); static EffectPlugin xmms_plugin = { .description = "Voice Removal Plugin", .mod_samples = apply_effect, + .query_format = query_format }; EffectPlugin *voice_eplist[] = { &xmms_plugin, NULL }; DECLARE_PLUGIN(voice_removal, NULL, NULL, NULL, NULL, voice_eplist, NULL, NULL, NULL); +static void query_format (AFormat *fmt, gint *rate, gint *nch) +{ + if (!((*fmt == FMT_S16_NE) || + (*fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) || + (*fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN))) + *fmt = FMT_S16_NE; + + if (*nch != 2) + *nch = 2; +} + static int apply_effect (gpointer *d, gint length, AFormat afmt, gint srate, gint nch) { int x;
--- a/src/vorbis/configure.c Thu May 22 19:31:48 2008 +0200 +++ b/src/vorbis/configure.c Thu May 22 19:32:39 2008 +0200 @@ -8,7 +8,6 @@ #include <string.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/i18n.h> extern GMutex *vf_mutex;
--- a/src/vorbis/vcupdate.c Thu May 22 19:31:48 2008 +0200 +++ b/src/vorbis/vcupdate.c Thu May 22 19:32:39 2008 +0200 @@ -33,8 +33,6 @@ #include <unistd.h> #include <audacious/plugin.h> -#include <audacious/strings.h> -#include <audacious/util.h> #include <audacious/i18n.h> #include <mowgli.h>
--- a/src/vorbis/vorbis.c Thu May 22 19:31:48 2008 +0200 +++ b/src/vorbis/vorbis.c Thu May 22 19:32:39 2008 +0200 @@ -54,9 +54,7 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> #include <audacious/i18n.h> -#include <audacious/strings.h> #include "vorbis.h"
--- a/src/vtx/about.c Thu May 22 19:31:48 2008 +0200 +++ b/src/vtx/about.c Thu May 22 19:32:39 2008 +0200 @@ -1,7 +1,5 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> -#include <audacious/strings.h> #include <audacious/i18n.h> #include <gtk/gtk.h>
--- a/src/vtx/info.c Thu May 22 19:31:48 2008 +0200 +++ b/src/vtx/info.c Thu May 22 19:32:39 2008 +0200 @@ -1,8 +1,6 @@ #include "ayemu.h" #include "vtx.h" -#include <audacious/util.h> #include <audacious/output.h> -#include <audacious/strings.h> #include <audacious/i18n.h> void vtx_file_info(gchar *filename)
--- a/src/vtx/vtx.c Thu May 22 19:31:48 2008 +0200 +++ b/src/vtx/vtx.c Thu May 22 19:32:39 2008 +0200 @@ -19,8 +19,6 @@ #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> -#include <audacious/strings.h> #include <audacious/i18n.h> #include "vtx.h"
--- a/src/wavpack/libwavpack.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/wavpack/libwavpack.cxx Thu May 22 19:32:39 2008 +0200 @@ -11,7 +11,6 @@ #include <wavpack/wavpack.h> #include <audacious/plugin.h> #include <audacious/output.h> -#include <audacious/util.h> } #include <glib.h> #include <gtk/gtk.h>
--- a/src/wavpack/tags.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/wavpack/tags.cxx Thu May 22 19:32:39 2008 +0200 @@ -4,7 +4,6 @@ #include <unistd.h> #include <fcntl.h> #include <wchar.h> -#include <audacious/util.h> #include <audacious/plugin.h> #include "tags.h"
--- a/src/wavpack/ui.cxx Thu May 22 19:31:48 2008 +0200 +++ b/src/wavpack/ui.cxx Thu May 22 19:32:39 2008 +0200 @@ -9,7 +9,6 @@ extern "C" { #include <wavpack/wavpack.h> #include <audacious/plugin.h> -#include <audacious/util.h> #include <audacious/i18n.h> } #include <glib.h>