Mercurial > audlegacy-plugins
changeset 900:d985f0dcdeb0 trunk
[svn] - add a starting point for xmms-rootvis port. giacomo will need to
finish this up, as my XLib skills are not enough at this time.
author | nenolod |
---|---|
date | Mon, 26 Mar 2007 01:19:26 -0700 |
parents | 68508f8cdf25 |
children | 08643d5994fe |
files | ChangeLog configure.ac mk/rules.mk.in src/rootvis/Makefile src/rootvis/config.h src/rootvis/config_backend.c src/rootvis/config_definition.c src/rootvis/config_frontend.c src/rootvis/config_frontend.h src/rootvis/config_frontend_widgets.c src/rootvis/getroot.c src/rootvis/rootvis.c src/rootvis/rootvis.h |
diffstat | 13 files changed, 2153 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Sun Mar 25 09:26:39 2007 -0700 +++ b/ChangeLog Mon Mar 26 01:19:26 2007 -0700 @@ -1,3 +1,10 @@ +2007-03-25 16:26:39 +0000 Giacomo Lozito <james@develia.org> + revision [1898] + - aosd: use XMapRaised in place of XMapWindow to ensure that the osd window is raised with some window managers + trunk/src/aosd/ghosd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + 2007-03-25 06:15:05 +0000 Yoshiki Yazawa <yaz@cc.rim.or.jp> revision [1896] - non-utf string had been used for file name in window title of File Info window. patch by M.H.
--- a/configure.ac Sun Mar 25 09:26:39 2007 -0700 +++ b/configure.ac Mon Mar 26 01:19:26 2007 -0700 @@ -387,6 +387,29 @@ GENERAL_PLUGINS="$GENERAL_PLUGINS aosd" fi +dnl *** Rootwindow vis plugin (imlib2 based) + +AC_ARG_ENABLE(rootvis, + [ --disable-rootvis disable X11 RootWindow vis plugin (default=enabled)], + [enable_rootvis=$enableval], + [enable_rootvis="yes"] +) + +if test "x$enable_rootvis" = "xyes"; then + have_rootvis="yes" + PKG_CHECK_MODULES(IMLIB2, [imlib2 >= 1.1.0],, + [have_rootvis="no" + AC_MSG_RESULT([*** imlib2 >= 1.1.0 is required for Audacious RootVis plugin ***])] + ) +else + AC_MSG_RESULT([*** RootVis plugin disabled per user request ***]) + have_rootvis="no" +fi + +if test "x$have_rootvis" = "xyes"; then + VISUALIZATION_PLUGINS="$VISUALIZATION_PLUGINS rootvis" +fi + dnl *** AdPlug requirement (libbinio) AC_ARG_ENABLE(adplug, @@ -1234,6 +1257,7 @@ echo " Spectrum Analyzer: yes" echo " Paranormal Visualization Library: $have_paranormal" echo " ProjectM (GL milkdrop): $have_projectm" +echo " RootVis plugin: $have_rootvis" echo echo " Transport" echo " ---------"
--- a/mk/rules.mk.in Sun Mar 25 09:26:39 2007 -0700 +++ b/mk/rules.mk.in Mon Mar 26 01:19:26 2007 -0700 @@ -351,3 +351,5 @@ MMS_LIBS ?= @MMS_LIBS@ MAD_CFLAGS ?= @MAD_CFLAGS@ MAD_LIBS ?= @MAD_LIBS@ +IMLIB2_CFLAGS ?= @IMLIB2_CFLAGS@ +IMLIB2_LIBS ?= @IMLIB2_LIBS@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/Makefile Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,22 @@ +include ../../mk/rules.mk +include ../../mk/init.mk + +OBJECTIVE_LIBS = librootvis.so + +CFLAGS += -I. $(PICFLAGS) $(GTK_CFLAGS) $(GLIB_CFLAGS) $(PANGO_CFLAGS) $(IMLIB2_CFLAGS) + +LIBDIR = $(plugindir)/$(VISUALIZATION_PLUGIN_DIR) + +LIBADD += $(GTK_LIBS) $(GLIB_LIBS) $(PANGO_LIBS) $(IMLIB2_LIBS) + +SOURCES = \ + config_backend.c \ + config_definition.c \ + config_frontend.c \ + config_frontend_widgets.c \ + getroot.c \ + rootvis.c + +OBJECTS = ${SOURCES:.c=.o} + +include ../../mk/objective.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/config.h Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,57 @@ +enum valtype { + BOOLN, + INT, + FLOAT, + TEXT, + COLOR +}; + +void config_init(void); +void config_revert(int); +void config_save(int); + +void config_show(int); + +struct config_value_int { + int* var; + int def_value; + int range[2]; +}; + +struct config_value_float { + float* var; + float def_value; + float range[2]; +}; + +struct config_value_text { + char** var; + char* def_value; + int maxlength; +}; + +struct config_value_color { + unsigned char* var; + char* def_value; + void* frontend; +}; + +struct config_value { + enum valtype type; + char* name; + int affects; + union { + struct config_value_int vali; + struct config_value_float valf; + struct config_value_text valt; + struct config_value_color valc; + }; +}; + +struct config_def { + int count; + struct config_value* def; +}; + +struct config_def Cmain; +struct config_def Cchannel[2];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/config_backend.c Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,172 @@ +#include <string.h> +#include <audacious/configdb.h> + +#include <rootvis.h> +#include <config.h> + +extern void config_def_init(void); +extern void config_frontend_init(void); + +void color_quad2arr(unsigned char* res, char* quad) { + if (sscanf(quad, "#%2hhx%2hhx%2hhx%2hhx", &res[0], &res[1], &res[2], &res[3]) != 4) + fprintf(stderr, "Color value %s could not be recognized as #rrggbbaa, ranging from #00000000 to #FFFFFFFF\n", quad); +} + +char* color_arr2quad(unsigned char* src, char* quad) { + sprintf(quad, "#%2.2hhx%2.2hhx%2.2hhx%2.2hhx", src[0], src[1], src[2], src[3]); + return quad; +} + +void cval_setdefault(struct config_value val) +{ + switch (val.type) + { + case BOOLN: + case INT: + *val.vali.var = val.vali.def_value; + break; + case FLOAT: + *val.valf.var = val.valf.def_value; + break; + case TEXT: + strcpy(*val.valt.var, val.valt.def_value); + break; + case COLOR: + color_quad2arr(val.valc.var, val.valc.def_value); + break; + } +} + +void cval_writefile(struct config_value val, ConfigDb *fp, char* sect) +{ + switch (val.type) + { + case BOOLN: + case INT: + bmp_cfg_db_set_int(fp, sect, val.name, *val.vali.var); + break; + case FLOAT: + bmp_cfg_db_set_float(fp, sect, val.name, *val.valf.var); + break; + case TEXT: + bmp_cfg_db_set_string(fp, sect, val.name, *val.valt.var); + break; + case COLOR: + { + char colortmp[10]; + bmp_cfg_db_set_string(fp, sect, val.name, color_arr2quad(val.valc.var, colortmp)); + } + break; + } +} + +void cval_readfile(struct config_value val, ConfigDb *fp, char* sect) +{ + switch (val.type) + { + case BOOLN: + case INT: + if (!(bmp_cfg_db_get_int(fp, sect, val.name, val.vali.var))) + cval_writefile(val, fp, sect); + break; + case FLOAT: + if (!(bmp_cfg_db_get_float(fp, sect, val.name, val.valf.var))) + cval_writefile(val, fp, sect); + break; + case TEXT: + if (!(bmp_cfg_db_get_string(fp, sect, val.name, val.valt.var))) + cval_writefile(val, fp, sect); + break; + case COLOR: + { + char* colortmp = NULL; + if (!(bmp_cfg_db_get_string(fp, sect, val.name, &colortmp))) + cval_writefile(val, fp, sect); + else color_quad2arr(val.valc.var, colortmp); + } + break; + } +} + +// this parses ~/.xmms/config +// if a setting is not found, it is created to make it possible to edit the default settings +// after the configuration dialogue is finished, this won't be necessary any more +void config_read(int number) { + int i, j; + ConfigDb *fp; + + fp = bmp_cfg_db_open(); + + print_status("Reading configuration"); + + if (number == 2) + for (i = 0; i < Cmain.count; ++i) + { + cval_setdefault(Cmain.def[i]); + cval_readfile(Cmain.def[i], fp, "rootvis"); + } + + for (j = 0; j < 2; ++j) + if ((number == j)||(number == 2)) + for (i = 0; i < Cchannel[j].count; ++i) + { + cval_setdefault(Cchannel[j].def[i]); + cval_readfile(Cchannel[j].def[i], fp, (j == 0 ? "rootvis" : "rootvis2")); + } + + bmp_cfg_db_close(fp); + print_status("Configuration finished"); +} + +void config_write(int number) { + int i, j; + ConfigDb *fp; + + print_status("Writing configuration"); + fp = bmp_cfg_db_open(); + + if (number == 2) + for (i = 0; i < Cmain.count; ++i) + cval_writefile(Cmain.def[i], fp, "rootvis"); + + for (j = 0; j < 2; ++j) + if ((number == j)||(number == 2)) + for (i = 0; i < Cchannel[j].count; ++i) + cval_writefile(Cchannel[j].def[i], fp, (j == 0 ? "rootvis" : "rootvis2")); + + bmp_cfg_db_close(fp); +} + +void config_revert(int number) { + /* as the configs aren't saved in a thread save way, we have to lock while we read them */ + threads_lock(); + config_read(number); + + // set the right change bits, according to wether we change channel 0, 1 or both (2) + if (number == 2) number = 15; + else number = 3 + number*9; + threads_unlock(number); +} + +void config_save(int number) { + threads_lock(); + config_write(number); + threads_unlock(0); +} + +void config_init(void) { + static int initialized = 0; + if (initialized == 0) { + print_status("First initialization"); + + conf.geo[0].display = malloc(256); + conf.geo[1].display = malloc(256); + + config_def_init(); + config_frontend_init(); + + config_read(2); + + initialized++; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/config_definition.c Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,152 @@ +#include <string.h> +#include <rootvis.h> +#include <config.h> + +inline void add_valb(struct config_def* conf, char* name, int affects, int* var, int def); +inline void add_vali(struct config_def* conf, char* name, int affects, int* var, int def, int from, int to); +inline void add_valf(struct config_def* conf, char* name, int affects, float* var, float def, float from, float to); +inline void add_valt(struct config_def* conf, char* name, int affects, char** var, char* def, int maxlen); +inline void add_valc(struct config_def* conf, char* name, int affects, unsigned char* var, char* def); + +void config_def_init(void) +{ + Cmain.count = 0; + add_valb(&Cmain, "debug", 0, &conf.debug, 0); + add_valb(&Cmain, "stereo", 32, &conf.stereo, 1); + + Cchannel[0].count = 0; + add_valt(&Cchannel[0], "geometry_display", 32, &conf.geo[0].display, "", 255); + add_vali(&Cchannel[0], "geometry_posx", 1, &conf.geo[0].posx, 520, 0, 0); + add_vali(&Cchannel[0], "geometry_posy", 1, &conf.geo[0].posy, 1, 0, 0); + add_vali(&Cchannel[0], "geometry_orientation", 1, &conf.geo[0].orientation, 0, 0, 3); + add_vali(&Cchannel[0], "geometry_height", 1, &conf.geo[0].height, 50, 0, 0); + add_vali(&Cchannel[0], "geometry_space", 1, &conf.geo[0].space, 1, 0, 0); + add_vali(&Cchannel[0], "bar_width", 1, &conf.bar[0].width, 8, 0, 0); + add_vali(&Cchannel[0], "bar_falloff", 0, &conf.bar[0].falloff, 5, 1, 0); + add_vali(&Cchannel[0], "bar_shadow", 1, &conf.bar[0].shadow, 1, 0, 0); + add_valb(&Cchannel[0], "bar_bevel", 0, &conf.bar[0].bevel, 0); + add_valb(&Cchannel[0], "bar_gradient", 0, &conf.bar[0].gradient, 1); + add_valc(&Cchannel[0], "bar_color_1", 2, conf.bar[0].color[0], "#e6ff64FF"); + add_valc(&Cchannel[0], "bar_color_2", 2, conf.bar[0].color[1], "#cdf62bFF"); + add_valc(&Cchannel[0], "bar_color_3", 2, conf.bar[0].color[2], "#b8dd27FF"); + add_valc(&Cchannel[0], "bar_color_4", 2, conf.bar[0].color[3], "#a3c422FF"); + add_valc(&Cchannel[0], "bar_bevel_color", 2, conf.bar[0].bevel_color, "#00FF00FF"); + add_valc(&Cchannel[0], "bar_shadow_color", 2, conf.bar[0].shadow_color, "#00000066"); + add_valb(&Cchannel[0], "peak_enabled", 1, &conf.peak[0].enabled, 1); + add_vali(&Cchannel[0], "peak_falloff", 0, &conf.peak[0].falloff, 4, 1, 0); + add_vali(&Cchannel[0], "peak_step", 0, &conf.peak[0].step, 5, 0, 0); + add_valc(&Cchannel[0], "peak_color", 2, conf.peak[0].color, "#ffffffdd"); + add_valb(&Cchannel[0], "peak_shadow", 0, &conf.peak[0].shadow, 0); + add_vali(&Cchannel[0], "data_cutoff", 1, &conf.data[0].cutoff, 180, 1, 255); + add_vali(&Cchannel[0], "data_div", 1, &conf.data[0].div, 4, 1, 255); + add_valf(&Cchannel[0], "data_linearity", 0, &conf.data[0].linearity, 0.33, 0.1, 0.9); + add_vali(&Cchannel[0], "data_fps", 0, &conf.data[0].fps, 30, 1, 100); + + Cchannel[1].count = 0; + add_valt(&Cchannel[1], "geometry_display", 32, &conf.geo[1].display, "", 255); + add_vali(&Cchannel[1], "geometry_posx", 1, &conf.geo[1].posx, 520, 0, 0); + add_vali(&Cchannel[1], "geometry_posy", 1, &conf.geo[1].posy, 52, 0, 0); + add_vali(&Cchannel[1], "geometry_orientation", 1, &conf.geo[1].orientation, 1, 0, 3); + add_vali(&Cchannel[1], "geometry_height", 1, &conf.geo[1].height, 40, 0, 0); + add_vali(&Cchannel[1], "geometry_space", 1, &conf.geo[1].space, 2, 0, 0); + add_vali(&Cchannel[1], "bar_width", 1, &conf.bar[1].width, 8, 0, 0); + add_vali(&Cchannel[1], "bar_falloff", 0, &conf.bar[1].falloff, 5, 1, 0); + add_vali(&Cchannel[1], "bar_shadow", 1, &conf.bar[1].shadow, 0, 0, 0); + add_valb(&Cchannel[1], "bar_bevel", 0, &conf.bar[1].bevel, 0); + add_valb(&Cchannel[1], "bar_gradient", 0, &conf.bar[1].gradient, 1); + add_valc(&Cchannel[1], "bar_color_1", 2, conf.bar[1].color[0], "#e6ff6466"); + add_valc(&Cchannel[1], "bar_color_2", 2, conf.bar[1].color[1], "#e6ff6455"); + add_valc(&Cchannel[1], "bar_color_3", 2, conf.bar[1].color[2], "#e6ff6433"); + add_valc(&Cchannel[1], "bar_color_4", 2, conf.bar[1].color[3], "#e6ff6422"); + add_valc(&Cchannel[1], "bar_bevel_color", 2, conf.bar[1].bevel_color, "#00FF00FF"); + add_valc(&Cchannel[1], "bar_shadow_color", 2, conf.bar[1].shadow_color, "#00000066"); + add_valb(&Cchannel[1], "peak_enabled", 1, &conf.peak[1].enabled, 1); + add_vali(&Cchannel[1], "peak_falloff", 0, &conf.peak[1].falloff, 4, 1, 0); + add_vali(&Cchannel[1], "peak_step", 0, &conf.peak[1].step, 5, 0, 0); + add_valc(&Cchannel[1], "peak_color", 2, conf.peak[1].color, "#ffffff88"); + add_valb(&Cchannel[1], "peak_shadow", 0, &conf.peak[1].shadow, 0); + add_vali(&Cchannel[1], "data_cutoff", 1, &conf.data[1].cutoff, 180, 1, 255); + add_vali(&Cchannel[1], "data_div", 1, &conf.data[1].div, 4, 1, 255); + add_valf(&Cchannel[1], "data_linearity", 0, &conf.data[1].linearity, 0.33, 0.1, 0.9); + add_vali(&Cchannel[1], "data_fps", 0, &conf.data[1].fps, 30, 1, 100); +} + +inline void add_begin(struct config_def* conf, char* name, int affects) +{ + conf->def = realloc(conf->def, (conf->count+1)*sizeof(struct config_value)); + conf->def[conf->count].name = (char*)malloc(strlen(name) + 1); + strcpy(conf->def[conf->count].name, name); + conf->def[conf->count].affects = affects; +} + +inline void add_end(struct config_def* conf) +{ + conf->count++; +} + +inline void add_valb(struct config_def* conf, char* name, int affects, int* var, int def) +{ + add_begin(conf, name, affects); + + conf->def[conf->count].type = BOOLN; + + conf->def[conf->count].vali.var = var; + conf->def[conf->count].vali.def_value = def; + + add_end(conf); +} + +inline void add_vali(struct config_def* conf, char* name, int affects, int* var, int def, int from, int to) +{ + add_begin(conf, name, affects); + + conf->def[conf->count].type = INT; + + conf->def[conf->count].vali.var = var; + conf->def[conf->count].vali.def_value = def; + conf->def[conf->count].vali.range[0] = from; + conf->def[conf->count].vali.range[1] = to; + + add_end(conf); +} + +inline void add_valf(struct config_def* conf, char* name, int affects, float* var, float def, float from, float to) +{ + add_begin(conf, name, affects); + + conf->def[conf->count].type = FLOAT; + + conf->def[conf->count].valf.var = var; + conf->def[conf->count].valf.def_value = def; + conf->def[conf->count].valf.range[0] = from; + conf->def[conf->count].valf.range[1] = to; + + add_end(conf); +} + +inline void add_valt(struct config_def* conf, char* name, int affects, char** var, char* def, int maxlen) +{ + add_begin(conf, name, affects); + + conf->def[conf->count].type = TEXT; + + conf->def[conf->count].valt.var = var; + conf->def[conf->count].valt.def_value = (char*)malloc(strlen(def) + 1); + strcpy(conf->def[conf->count].valt.def_value, def); + conf->def[conf->count].valt.maxlength = maxlen; + + add_end(conf); +} + +inline void add_valc(struct config_def* conf, char* name, int affects, unsigned char* var, char* def) +{ + add_begin(conf, name, affects); + + conf->def[conf->count].type = COLOR; + + conf->def[conf->count].valc.var = var; + conf->def[conf->count].valc.def_value = (char*)malloc(strlen(def) + 1); + strcpy(conf->def[conf->count].valc.def_value, def); + + add_end(conf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/config_frontend.c Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,210 @@ +#include <stdarg.h> +#include <string.h> + +#include <rootvis.h> + +#include <config_frontend.h> + +extern GtkWidget *frontend_create_channel(int channel); +extern GtkWidget *frontend_create_main(void); +extern void frontend_create_colorpicker(struct config_value*); + +void signal_revert(GtkWidget *togglebutton, gpointer data) +{ + config_revert(GPOINTER_TO_INT(data)); +} + +void signal_save(GtkWidget *togglebutton, gpointer data) +{ + config_save(GPOINTER_TO_INT(data)); +} + +void signal_show(GtkWidget *togglebutton, gpointer data) +{ + config_show(GPOINTER_TO_INT(data)); +} + +void signal_hide(GtkWidget *togglebutton, gpointer data) +{ + config_hide(GPOINTER_TO_INT(data)); +} + +void signal_toggle_colorselector(GtkWidget *w, struct config_value *cvar) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + if (colorsel->window == NULL) + frontend_create_colorpicker(cvar); + gtk_widget_show(colorsel->window); +} + +void signal_colorselector_ok(GtkWidget *w, struct config_value *cvar) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + gtk_color_selection_get_color(GTK_COLOR_SELECTION(colorsel->color_picker), colorsel->color); + memcpy(colorsel->saved_color, colorsel->color, COLORSIZE*sizeof(gdouble)); + frontend_update_color(cvar, 1); + gtk_widget_hide(colorsel->window); +} + +void signal_colorselector_cancel(GtkWidget *w, struct config_value *cvar) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + memcpy(colorsel->color, colorsel->saved_color, COLORSIZE*sizeof(gdouble)); + frontend_update_color(cvar, 1); + gtk_widget_destroy(colorsel->window); + colorsel->window = NULL; +} + +void signal_colorselector_update(GtkWidget *w, struct config_value *cvar) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + gtk_color_selection_get_color(GTK_COLOR_SELECTION(colorsel->color_picker), colorsel->color); + frontend_update_color(cvar, 1); +} + +void color_char2double(unsigned char source[4], gdouble dest[4]) +{ + int i; + for (i = 0; i < COLORSIZE; ++i) + { + dest[i] = (double)source[i] / 255.0; + } +} + +void color_double2char(double source[4], unsigned char dest[4]) +{ + int i; + for (i = 0; i < COLORSIZE; ++i) + { + dest[i] = (int)(source[i] * 255.0); + } +} + +// This was ripped from xmms-iris's config.c. +void frontend_update_color(struct config_value *cvar, int system) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + if (system > 0) + { + threads_lock(); + color_double2char(colorsel->color, cvar->valc.var); + threads_unlock(2); + } + + // following is among the dumbest shit I've ever seen. GtkPreview seems to suck a lot! + unsigned int i; + guchar color_buf[3*30]; + char red, green, blue; + red = colorsel->color[RED]*0xff; + green = colorsel->color[GREEN]*0xff; + blue = colorsel->color[BLUE]*0xff; + for (i = 0; i < 30*3; i += 3) { + color_buf[i+RED] = (char) red; + color_buf[i+GREEN] = (char) green; + color_buf[i+BLUE] = (char) blue; + } + for (i = 0; i < 30; i++) + gtk_preview_draw_row(GTK_PREVIEW(colorsel->preview), color_buf, 0, i, 30); + gtk_widget_draw(colorsel->preview, NULL); +} + +void frontend_set_color(struct config_value *cvar) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + color_char2double(cvar->valc.var, colorsel->color); + memcpy(colorsel->saved_color, colorsel->color, COLORSIZE*sizeof(gdouble)); +} + +/* following functions catch signals from the gui widgets */ + +int signal_window_close(GtkWidget *window, gpointer data) +{ + int number = 2; + if (window == widgets.window_channel[0]) number = 0; + if (window == widgets.window_channel[1]) number = 1; + config_hide(number); + return TRUE; +} + +void signal_check_toggled(GtkWidget *togglebutton, gpointer data) +{ + printf("%s \n", (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton))) ? "TRUE" : "FALSE"); +} + +void signal_stereo_toggled(GtkWidget *togglebutton, gpointer data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton))) { + gtk_label_set_text(widgets.stereo_status[0], "renders left channel"); + gtk_label_set_text(widgets.stereo_status[1], "renders right channel"); + } else { + gtk_label_set_text(widgets.stereo_status[0], "renders both channels"); + gtk_label_set_text(widgets.stereo_status[1], "unused / inactive"); + } +} + +void signal_textentry_changed(GtkWidget *entry, gpointer data) +{ +} + +void config_show_channel(int channel) { + if (widgets.window_channel[channel] == NULL) { + widgets.window_channel[channel] = frontend_create_channel(channel); + } else { + print_status("raising channel window"); + gtk_widget_show(widgets.window_channel[channel]); + } +} + +void config_show(int channel) { + if (channel == 2) + { + if (widgets.window_main == NULL) { + widgets.window_main = frontend_create_main(); + } else { + print_status("raising windows"); + gtk_widget_show(widgets.window_main); + if (widgets.window_channel[0] != NULL) { + gtk_widget_show(widgets.window_channel[0]); + } + if (widgets.window_channel[1] != NULL) { + gtk_widget_show(widgets.window_channel[1]); + } + } + } else config_show_channel(channel); +} + +void config_hide(int number) { + /* hide or destroy? if destroy, pointers must be set to NULL */ + if (number < 2) { + if (widgets.window_channel[number] != NULL) + gtk_widget_hide(widgets.window_channel[number]); + /* widgets.window_channel[number] = NULL; */ + } else { + if (widgets.window_main != NULL) + gtk_widget_hide(widgets.window_main); + if (widgets.window_channel[0] != NULL) + gtk_widget_hide(widgets.window_channel[0]); + if (widgets.window_channel[1] != NULL) + gtk_widget_hide(widgets.window_channel[1]); + widgets.window_main = NULL; + widgets.window_channel[0] = NULL; + widgets.window_channel[1] = NULL; + // THIS SUCKS BEYOND REPAIR! + } +} + +void config_set_widgets(int number) +{ + if (number < 2) { + // set per channel stuff + } else { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widgets.stereo_check), ((conf.stereo>0) ? TRUE : FALSE)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widgets.debug_check), ((conf.debug>0) ? TRUE : FALSE)); + } +} + +void config_frontend_init(void) { + widgets.window_main = NULL; + widgets.window_channel[0] = NULL; + widgets.window_channel[1] = NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/config_frontend.h Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,62 @@ +#include <config.h> + +#define VBOX 1 +#define HBOX 2 +#define HBBOX 3 +#define HBBOX2 4 +#define VBBOX 5 +#define FRAME 6 + +#define ATTACH_TO_NOTEBOOK 1 +#define ATTACH_TO_CONTAINER 2 +#define ATTACH_TO_BOX 3 + +#define ENTRY 1 +#define COMBO 2 + +// this struct contains all we need to change a color: +struct rootvis_colorsel +{ + GtkWidget *preview; // the preview we need to update. + GtkWidget *button; // the button that made it all + // ( to keep pressed ). FIXME + GtkWidget *label; // the name left of the button. + GtkWidget *color_picker; // the colorpicker that was launched. + GtkWidget *window; // the window we launched. + gdouble color[4]; // the color. + gdouble saved_color[4]; + char *name; // the name. + // (we'll use this to tune the colorpicker). + char *complete_name; // this is for the window's title. +}; + +// this is to contain pointers to various widgets... +struct rootvis_frontend +{ + GtkWidget *window_main; + GtkWidget *window_channel[2]; + GtkWidget *stereo_status[2]; + GtkWidget *stereo_check; + GtkWidget *debug_check; +} widgets; + +void config_hide(int); +void config_set_widgets(int); + +int signal_window_close(GtkWidget *window, gpointer data); +void signal_check_toggled(GtkWidget *togglebutton, gpointer data); +void signal_stereo_toggled(GtkWidget *togglebutton, gpointer data); +void signal_textentry_changed(GtkWidget *entry, gpointer data); +void signal_toggle_colorselector(GtkWidget *button, struct config_value* cvar); +void signal_colorselector_ok(GtkWidget *button, struct config_value* cvar); +void signal_colorselector_cancel(GtkWidget *button, struct config_value* cvar); +void signal_colorselector_update(GtkWidget *w, struct config_value* cvar); + +void signal_revert(GtkWidget *togglebutton, gpointer data); +void signal_save(GtkWidget *togglebutton, gpointer data); +void signal_show(GtkWidget *togglebutton, gpointer data); +void signal_hide(GtkWidget *togglebutton, gpointer data); + + +void frontend_update_color(struct config_value* cvar, int system); +void frontend_set_color(struct config_value* cvar);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/config_frontend_widgets.c Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,486 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gtk/gtk.h> +#include <config_frontend.h> + +extern void print_status(char msg[]); + +void frontend_set_signal(GtkWidget *widget, char* signal, void* func, int data) +{ + gtk_signal_connect(GTK_OBJECT(widget), signal, GTK_SIGNAL_FUNC(func), GINT_TO_POINTER(data)); +} + +GtkWidget *frontend_create_window(int type, const char *name) +{ + GtkWidget *window; + + print_status("creating window"); + print_status(name); + window = gtk_window_new(type); + gtk_signal_connect(GTK_OBJECT(window), + "delete-event", + GTK_SIGNAL_FUNC(signal_window_close), + NULL); + + print_status("setting title"); + gtk_window_set_title(window, name); + print_status("done"); + gtk_widget_show(window); + return window; +} + +GtkWidget *frontend_create_box(int box_type, GtkWidget *container, char *label, + int attach) +{ + GtkWidget *box; + + print_status("creating box"); + print_status(label); + + + + switch (box_type) { + case VBOX: + box = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(box), 5); + break; + + case HBOX: + box = gtk_hbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(box), 5); + break; + case HBBOX: + box = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(box), + GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(box), 5); + break; + case HBBOX2: + box = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(box), + GTK_BUTTONBOX_EDGE); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(box), 4); + break; + case FRAME: + box = gtk_frame_new(label); + gtk_container_set_border_width(GTK_CONTAINER(box), 5); + break; + default: + print_status("error"); + print_status("trying to create vbox"); + box = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(box), 5); + } + + print_status("attaching"); + switch (attach) { + case ATTACH_TO_NOTEBOOK: + gtk_notebook_append_page(GTK_NOTEBOOK(container), + box, gtk_label_new(label)); + break; + + case ATTACH_TO_CONTAINER: + gtk_container_add(GTK_CONTAINER(container), box); + break; + case ATTACH_TO_BOX: + gtk_box_pack_start(GTK_BOX(container), box, TRUE, TRUE, 0); + break; + default: + print_status("error"); + print_status("trying to attach to container"); + gtk_container_add(GTK_CONTAINER(container), box); + } + gtk_widget_show(box); + print_status("done"); + return box; +} + +GtkWidget *frontend_create_notebook(GtkWidget *box) +{ + GtkWidget *notebook; + + print_status("creating notebook"); + notebook = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0); + gtk_widget_show(notebook); + return notebook; +} + +GtkWidget *frontend_create_button(GtkWidget *container, char *label) +{ + GtkWidget *button; + + print_status("adding button"); + print_status(label); + + button = gtk_button_new_with_label(label); + gtk_widget_show(button); + + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(container), button, TRUE, TRUE, 0); + + return button; +} + +GtkWidget *frontend_create_check(GtkWidget *container, char *label) +{ + GtkWidget *check; + + print_status("creating check"); + print_status(label); + + check = gtk_check_button_new_with_label(label); + gtk_widget_show(check); + + gtk_container_add(GTK_CONTAINER(container), check); + + print_status("done"); + return check; +} + +GtkWidget *frontend_create_label(GtkWidget *container, char *text) +{ + GtkWidget *label; + + print_status("creating label"); + print_status(text); + + label = gtk_label_new(text); + gtk_label_set_justify(label, GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap(label, TRUE); + gtk_widget_show(label); + + gtk_container_add(GTK_CONTAINER(container), label); + + print_status("done"); + return label; +} + +/* +GtkWidget *rootvis_create_frame_and_attach(char *name, GtkWidget *box) +{ + GtkWidget *frame; + + frame = gtk_frame_new(name); + gtk_container_set_border_width(GTK_CONTAINER(frame), 5); + gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0); + gtk_widget_show(frame); + return frame; +} +*/ + +GtkWidget *frontend_create_entry(int type, GtkWidget *container, + char *entry_changed, + char *label, ...) +{ + va_list ap; + char *list_element; + char *signal; + + GtkWidget *entry; + GList *list = NULL; + + print_status("creating entry"); + print_status(label); + + va_start(ap, label); + switch (type) { + case COMBO: + entry = gtk_combo_new(); + while ((list_element = va_arg(ap, char *))) { + print_status("adding element to list"); + print_status(list_element); + list = g_list_append(list, list_element); + } + print_status("attaching string list to combo"); + gtk_combo_set_popdown_strings(GTK_COMBO(entry), list); + break; + case ENTRY: + entry = gtk_entry_new(); + gtk_entry_set_max_length(GTK_ENTRY(entry), 6); + while ((signal = va_arg(ap, char *))) { + print_status("adding signal to entry"); + print_status(signal); + gtk_signal_connect(GTK_OBJECT(entry), + /* signal */ + signal, + /* function */ + GTK_SIGNAL_FUNC(va_arg(ap, + void *)), + /* data */ + va_arg(ap, char *)); + } + break; + default: + return NULL; + } + va_end(ap); + + print_status("attaching entry to container"); + gtk_container_add(GTK_CONTAINER(container), entry); + gtk_widget_show(entry); + + print_status("done"); + + return entry; +} + +void frontend_create_colorpicker(struct config_value *cvar) +{ + struct rootvis_colorsel* colorsel = cvar->valc.frontend; + GtkWidget *vbox; + GtkWidget *options_frame, *options_vbox; + + static GtkWidget *bbox, *ok, *cancel; + + print_status("pressing button ... "); + gtk_button_set_relief(GTK_BUTTON(colorsel->button), GTK_RELIEF_HALF); + + + print_status("casting window ..."); + + colorsel->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(colorsel->window), colorsel->complete_name); + + gtk_container_set_border_width(GTK_CONTAINER(colorsel->window), 10); + gtk_window_set_policy(GTK_WINDOW(colorsel->window), FALSE, FALSE, FALSE); + gtk_window_set_position(GTK_WINDOW(colorsel->window), + GTK_WIN_POS_MOUSE); + gtk_signal_connect(GTK_OBJECT(colorsel->window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &(colorsel->window)); + + vbox = gtk_vbox_new(FALSE, 5); + + printf("setting name ..."); + options_frame = gtk_frame_new(colorsel->complete_name); + printf("done. \n"); + gtk_container_set_border_width(GTK_CONTAINER(options_frame), 5); + + options_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(options_vbox), 5); + + colorsel->color_picker = gtk_color_selection_new(); + gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(colorsel->color_picker), TRUE); + gtk_color_selection_set_color(GTK_COLOR_SELECTION(colorsel->color_picker), colorsel->color); + gtk_signal_connect(GTK_OBJECT(colorsel->color_picker), "color_changed", GTK_SIGNAL_FUNC(signal_colorselector_update), cvar); + + gtk_box_pack_start(GTK_BOX(options_vbox), colorsel->color_picker, + FALSE, FALSE, 0); + gtk_widget_show(colorsel->color_picker); + printf("raising the curtain \n"); + + gtk_container_add(GTK_CONTAINER(options_frame), options_vbox); + gtk_widget_show(options_vbox); + + gtk_box_pack_start(GTK_BOX(vbox), options_frame, TRUE, TRUE, 0); + gtk_widget_show(options_frame); + + 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); + + ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(signal_colorselector_ok), cvar); + GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); + gtk_widget_show(ok); + + + cancel = gtk_button_new_with_label("Cancel"); + gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(signal_colorselector_cancel), cvar); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); + gtk_widget_show(cancel); + gtk_widget_show(bbox); + + gtk_container_add(GTK_CONTAINER(colorsel->window), vbox); + gtk_widget_show(vbox); + gtk_widget_grab_default(ok); +} + +void frontend_create_color_button(struct config_value* cvar, GtkWidget *container, char *name, + char *channel_name) +{ + struct rootvis_colorsel *color_struct; + + print_status("Allocating memory for color struct"); + color_struct = malloc(sizeof(struct rootvis_colorsel)); + cvar->valc.frontend = color_struct; + + frontend_set_color(cvar); + color_struct->window = NULL; + color_struct->name = name; //complete_name; + + print_status("reallocating name"); + color_struct->complete_name = + malloc((sizeof(name) + sizeof(channel_name) + 10)*sizeof(char)); + print_status("done"); + sprintf(color_struct->complete_name, "%s - %s", channel_name, name); + print_status("done"); + + + char* labeltext = (char*)malloc(strlen(name) + 2); + sprintf(labeltext, "%s:", name); + color_struct->label = gtk_label_new(labeltext); + gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(color_struct->label)); + + color_struct->button = gtk_button_new(); + print_status("adding container ... "); + gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(color_struct->button)); + print_status("done.\nraising ... "); + + print_status("done.\nmaking preview ... "); + + color_struct->preview = gtk_preview_new(GTK_PREVIEW_COLOR); + print_status("done.\nsetting size ... "); + gtk_preview_size(GTK_PREVIEW(color_struct->preview), 30, 28); + print_status("done.\nraising ... "); + print_status("done.\n"); + gtk_container_add(GTK_CONTAINER(color_struct->button), color_struct->preview); + + gtk_widget_set_usize(color_struct->button, 32, 26); + + gtk_signal_connect(GTK_OBJECT(color_struct->button), "clicked", + GTK_SIGNAL_FUNC(signal_toggle_colorselector), cvar); + + frontend_update_color(cvar, 0); + gtk_widget_show(GTK_WIDGET(color_struct->label)); + gtk_widget_show(GTK_WIDGET(color_struct->button)); + gtk_widget_show(color_struct->preview); +} + +GtkWidget *frontend_create_channel(int channel) +{ + GtkWidget *window; + char name[12]; + + print_status("creating gtk window ... "); + + sprintf(name, "Channel %d", channel+1); + print_status(name); + + print_status("debug 2"); + + window = frontend_create_window(GTK_WINDOW_TOPLEVEL, &name); + + print_status("done."); + + { + GtkWidget *vbox_0, *notebook_1, *button_box_1, + *vbox_2[4], *frame_3[4], *vbox_3[1], *hbox_4[5], + *check_debug, *check_stereo, + *close_button, *revert_button; + + vbox_0 = frontend_create_box(VBOX, window, "rootvis_config_vbox", ATTACH_TO_CONTAINER); + { + + notebook_1 = frontend_create_notebook(vbox_0); + { + /* vbox_2[0] = frontend_create_box(VBOX, notebook_1, "General", ATTACH_TO_NOTEBOOK); + { + } + vbox_2[1] = frontend_create_box(VBOX, notebook_1, "Geometry", ATTACH_TO_NOTEBOOK); + { + } + vbox_2[2] = frontend_create_box(VBOX, notebook_1, "Look & Feel", ATTACH_TO_NOTEBOOK); + { + }*/ + vbox_2[3] = frontend_create_box(VBOX, notebook_1, "Colors", ATTACH_TO_NOTEBOOK); + { + frame_3[0] = frontend_create_box(FRAME, vbox_2[3], "Gradient", ATTACH_TO_BOX); + hbox_4[0] = frontend_create_box(HBOX, frame_3[0], "Bar", ATTACH_TO_CONTAINER); + { + frontend_create_color_button(&Cchannel[channel].def[11], hbox_4[0], "Begin", name); + frontend_create_color_button(&Cchannel[channel].def[12], hbox_4[0], "2/5", name); + frontend_create_color_button(&Cchannel[channel].def[13], hbox_4[0], "4/5", name); + frontend_create_color_button(&Cchannel[channel].def[14], hbox_4[0], "End", name); + } + frame_3[1] = frontend_create_box(FRAME, vbox_2[3], "Bevel, Peaks & Shadow", ATTACH_TO_BOX); + hbox_4[1] = frontend_create_box(HBOX, frame_3[1], "etc", ATTACH_TO_CONTAINER); + { + frontend_create_color_button(&Cchannel[channel].def[15], hbox_4[1], "Bevel", name); + frontend_create_color_button(&Cchannel[channel].def[20], hbox_4[1], "Peaks", name); + frontend_create_color_button(&Cchannel[channel].def[16], hbox_4[1], "Shadow", name); + } + } + } + + + button_box_1 = frontend_create_box(HBBOX2, vbox_0, "Button Box", ATTACH_TO_BOX); + { + revert_button = frontend_create_button(button_box_1, "Revert"); + frontend_set_signal(revert_button, "clicked", signal_revert, channel); + close_button = frontend_create_button(button_box_1, "Close"); + frontend_set_signal(close_button, "clicked", signal_hide, channel); + } + } + } + config_set_widgets(channel); + return window; +} + +GtkWidget *frontend_create_main(void) +{ + GtkWidget *window, *channel_button[2], + *button_box[2], *channels_frame, *main_frame, *vbox, + *main_vbox, *channels_hbox, *channel_vbox[2], + *save_button, *revert_button, *close_button; + + window = frontend_create_window(GTK_WINDOW_TOPLEVEL, "Main"); + { + vbox = frontend_create_box(VBOX, window, "vbox", ATTACH_TO_CONTAINER); + { + main_frame = frontend_create_box(FRAME, vbox, "Global Settings", ATTACH_TO_BOX); + { + main_vbox = frontend_create_box(VBOX, main_frame, "main_hbox", + ATTACH_TO_CONTAINER); + + widgets.stereo_check = frontend_create_check(main_vbox, "stereo support"); + frontend_set_signal(widgets.stereo_check, "toggled", signal_stereo_toggled, 0); + widgets.debug_check = frontend_create_check(main_vbox, "debug messages (stdout)"); + frontend_set_signal(widgets.debug_check, "toggled", signal_check_toggled, 0); + + } + channels_frame = frontend_create_box(FRAME, vbox, "Channel-specific", + ATTACH_TO_BOX); + { + button_box[0] = frontend_create_box(HBOX, channels_frame, "Main Button Box", + ATTACH_TO_CONTAINER); + { + channel_vbox[0] = frontend_create_box(VBOX, button_box[0], "channel_vbox_0", + ATTACH_TO_CONTAINER); + { + channel_button[0] = frontend_create_button(channel_vbox[0], "First Channel"); + frontend_set_signal(channel_button[0], "clicked", signal_show, 0); + widgets.stereo_status[0] = frontend_create_label(channel_vbox[0], "renders both channels"); + } + channel_vbox[1] = frontend_create_box(VBOX, button_box[0], "channel_vbox_0", + ATTACH_TO_CONTAINER); + { + + channel_button[1] = frontend_create_button(channel_vbox[1], "Second Channel"); + frontend_set_signal(channel_button[1], "clicked", signal_show, 1); + widgets.stereo_status[1] = frontend_create_label(channel_vbox[1], "unused / inactive"); + } + } + } + button_box[1] = frontend_create_box(HBBOX, vbox, "Button Box", ATTACH_TO_BOX); + { + + revert_button = frontend_create_button(button_box[1], "Revert All"); + frontend_set_signal(revert_button, "clicked", signal_revert, 2); + save_button = frontend_create_button(button_box[1], "Save Settings"); + frontend_set_signal(save_button, "clicked", signal_save, 2); + close_button = frontend_create_button(button_box[1], "Close Windows"); + frontend_set_signal(close_button, "clicked", signal_hide, 2); + + } + } + } + config_set_widgets(2); + return window; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/getroot.c Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,400 @@ +/* I've modified the following file and renamed it. My modifications were just + * about getting rid of some toon.h dependants. If you're interested in the + * original version of the file, you can find it either in the sources of + * xpenguins or of xsnow. + * http://xpenguins.seul.org/ is my actual source. + * + * Johannes Jordan + */ + +/* toon_root.c - finding the correct background window / virtual root + * Copyright (C) 1999-2001 Robin Hogan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Since xpenguins version 2.1, the ToonGetRootWindow() function + * attempts to find the window IDs of + * + * 1) The background window that is behind the toplevel client + * windows; this is the window that we draw the toons on. + * + * 2) The parent window of the toplevel client windows; this is used + * by ToonLocateWindows() to build up a map of the space that the + * toons can occupy. + * + * In simple (sensible?) window managers (e.g. blackbox, sawfish, fvwm + * and countless others), both of these are the root window. The other + * more complex scenarios that ToonGetRootWindow() attempts to cope + * with are: + * + * Some `virtual' window managers (e.g. amiwm, swm and tvtwm) that + * reparent all client windows to a desktop window that sits on top of + * the root window. This desktop window is easy to find - we just look + * for a property __SWM_VROOT in the immediate children of the root + * window that contains the window ID of this desktop window. The + * desktop plays both roles (1 and 2 above). This functionality was + * detected in xpenguins 1.x with the vroot.h header file. + * + * Enlightenment (0.16) can have a number of desktops with different + * backgrounds; client windows on these are reparented, except for + * Desktop 0 which is the root window. Therefore versions less than + * 2.1 of xpenguins worked on Desktop 0 but not on any others. To fix + * this we look for a root-window property _WIN_WORKSPACE which + * contains the numerical index of the currently active desktop. The + * active desktop is then simply the immediate child of the root + * window that has a property ENLIGHTENMENT_DESKTOP set to this value. + * + * KDE 2.0: Oh dear. The kdesktop is a program separate from the + * window manager that launches a window which sits behind all the + * other client windows and has all the icons on it. Thus the other + * client windows are still children of the root window, but we want + * to draw to the uppermost window of the kdesktop. This is difficult + * to find - it is the great-great-grandchild of the root window and + * in KDE 2.0 has nothing to identify it from its siblings other than + * its size. KDE 2.1+ usefully implements the __SWM_VROOT property in + * a child of the root window, but the client windows are still + * children of the root window. A problem is that the penguins erase + * the desktop icons when they walk which is a bit messy. The icons + * are not lost - they reappear when the desktop window gets an expose + * event (i.e. move some windows over where they were and back again). + * + * Nautilus (GNOME 1.4+): Creates a background window to draw icons + * on, but does not reparent the client windows. The toplevel window + * of the desktop is indicated by the root window property + * NAUTILUS_DESKTOP_WINDOW_ID, but then we must descend down the tree + * from this toplevel window looking for subwindows that are the same + * size as the screen. The bottom one is the one to draw to. Hopefully + * one day Nautilus will implement __SWM_VROOT in exactly the same way + * as KDE 2.1+. + * + * Other cases: CDE, the common desktop environment. This is a + * commercial product that has been packaged with Sun (and other) + * workstations. It typically implements four virtual desktops but + * provides NO properties at all for apps such as xpenguins to use to + * work out where to draw to. Seeing as Sun are moving over to GNOME, + * CDE use is on the decline so I don't have any current plans to try + * and get xpenguins to work with it. + * + * As a note to developers of window managers and big screen hoggers + * like kdesktop, please visit www.freedesktop.org and implement their + * Extended Window Manager Hints spec that help pagers and apps like + * xpenguins and xearth to find their way around. In particular, + * please use the _NET_CURRENT_DESKTOP and _NET_VIRTUAL_ROOTS + * properties if you reparent any windows (e.g. Enlightenment). Since + * no window managers that I know yet use these particular hints, I + * haven't yet added any code to parse them. */ + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xproto.h> +#include <string.h> + +/* Time to throw up. Here is a kludgey function that recursively calls + * itself (up to a limit) to find the window ID of the KDE desktop to + * draw on. It works with KDE 2.0, but since KDE 2.0 is less stable + * than Windows 95, I don't expect many people to remain using it now + * that 2.1 is available, which implements __SWM_VROOT and makes this + * function redundant. This is the hierarchy we're trying to traverse: + * + * -> The root window + * 0 -> window with name="KDE Desktop" + * 1 -> window with no name + * 2 -> window with name="KDE Desktop" & _NET_WM_WINDOW_TYPE_DESKTOP + * 3 -> window with no name and width >= width of screen + * + * The last window in the hierarchy is the one to draw to. The + * numbers show the value of the `depth' argument. */ +static +Window +__ToonGetKDEDesktop(Display *display, int screen, Window window, + Atom atom, char *atomname, int depth) +{ + char *name = NULL; + unsigned char *wintype = NULL; + Window winreturn = 0; + unsigned long nitems, bytesafter; + Atom actual_type; + int actual_format; + Window rootReturn, parentReturn, *children; + unsigned int nChildren; + char go_deeper = 0; + + if (XFetchName(display, window, &name)) { + if (strcasecmp(name, "KDE Desktop") == 0) { + /* Presumably either at depth 0 or 2 */ + if (XGetWindowProperty(display, window, atom, 0, 1, + False, XA_ATOM, + &actual_type, &actual_format, + &nitems, &bytesafter, + &wintype) == Success + && wintype) { + char *tmpatomname = XGetAtomName(display, *(Atom*)wintype); + if (tmpatomname) { + if (strcmp(atomname, tmpatomname) == 0 && depth == 2) { + /* OK, at depth 2 */ + go_deeper = 1; + } + XFree((char *) tmpatomname); + } + } + else if (depth < 2) { + go_deeper = 1; + } + } + else if (depth == 1) { + go_deeper = 1; + } + XFree((char *) name); + } + else if (depth == 1) { + go_deeper = 1; + } + + /* If go_deeper is 1 then there is a possibility that the background + * window is a descendant of the current window; otherwise we're + * barking up the wrong tree. */ + if (go_deeper && XQueryTree(display, window, &rootReturn, + &parentReturn, &children, + &nChildren)) { + int i; + for (i = 0; i < nChildren; ++i) { + /* children[i] is now at depth 3 */ + if (depth == 2) { + XWindowAttributes attributes; + if (XGetWindowAttributes(display, children[i], &attributes)) { + if (attributes.width >= DisplayWidth(display, screen)/2 + && attributes.height > 0) { + /* Found it! */ + winreturn = children[i]; + break; + } + } + } + else if ((winreturn = __ToonGetKDEDesktop(display, screen, + children[i], + atom, atomname, + depth+1))) { + break; + } + } + XFree((char *) children); + } + + return winreturn; +} + +/* Look for the Nautilus desktop window to draw to, given the toplevel + * window of the Nautilus desktop. Basically recursively calls itself + * looking for subwindows the same size as the root window. */ +static +Window +__ToonGetNautilusDesktop(Display *display, int screen, Window window, + int depth) +{ + Window rootReturn, parentReturn, *children; + Window winreturn = window; + unsigned int nChildren; + + if (depth > 5) { + return ((Window) 0); + } + else if (XQueryTree(display, window, &rootReturn, &parentReturn, + &children, &nChildren)) { + int i; + for (i = 0; i < nChildren; ++i) { + XWindowAttributes attributes; + if (XGetWindowAttributes(display, children[i], &attributes)) { + if (attributes.width == DisplayWidth(display, screen) + && attributes.height == DisplayHeight(display, screen)) { + /* Found a possible desktop window */ + winreturn = __ToonGetNautilusDesktop(display, screen, + children[i], depth+1); + } + } + } + XFree((char *) children); + } + return winreturn; +} + + +/* + * Returns the window ID of the `background' window on to which the + * toons should be drawn. Also returned (in clientparent) is the ID of + * the parent of all the client windows, since this may not be the + * same as the background window. If no recognised virtual window + * manager or desktop environment is found then the root window is + * returned in both cases. The string toon_message contains + * information about the window manager that was found. + */ +Window +ToonGetRootWindow(Display *display, int screen, Window *clientparent) +{ + Window background = 0; /* The return value */ + Window root = RootWindow(display, screen); + Window rootReturn, parentReturn, *children; + unsigned char *toplevel = NULL; + unsigned int nChildren; + unsigned long nitems, bytesafter; + Atom actual_type; + int actual_format; + unsigned char *workspace = NULL; + unsigned char *desktop = NULL; + Atom NAUTILUS_DESKTOP_WINDOW_ID = XInternAtom(display, + "NAUTILUS_DESKTOP_WINDOW_ID", + False); + + *clientparent = root; + + if (XGetWindowProperty(display, root, + NAUTILUS_DESKTOP_WINDOW_ID, + 0, 1, False, XA_WINDOW, + &actual_type, &actual_format, + &nitems, &bytesafter, + &toplevel) == Success + && toplevel) { + /* Nautilus is running */ + background = __ToonGetNautilusDesktop(display, screen, + *(Window*)toplevel, 0); + XFree(toplevel); + } + + /* Next look for a virtual root or a KDE Desktop */ + if (!background + && XQueryTree(display, root, &rootReturn, &parentReturn, + &children, &nChildren)) { + int i; + Atom _NET_WM_WINDOW_TYPE = XInternAtom(display, + "_NET_WM_WINDOW_TYPE", + False); + Atom __SWM_VROOT = XInternAtom(display, "__SWM_VROOT", False); + + for (i = 0; i < nChildren && !background; ++i) { + unsigned char *newroot = NULL; + if (XGetWindowProperty(display, children[i], + __SWM_VROOT, 0, 1, False, XA_WINDOW, + &actual_type, &actual_format, + &nitems, &bytesafter, + &newroot) == Success + && newroot) { + /* Found a window with a __SWM_VROOT property that contains + * the window ID of the virtual root. Now we must check + * whether it is KDE (2.1+) or not. If it is KDE then it does + * not reparent the clients. If the root window has the + * _NET_SUPPORTED property but not the _NET_VIRTUAL_ROOTS + * property then we assume it is KDE. */ + Atom _NET_SUPPORTED = XInternAtom(display, + "_NET_SUPPORTED", + False); + unsigned char *tmpatom; + if (XGetWindowProperty(display, root, + _NET_SUPPORTED, 0, 1, False, + XA_ATOM, &actual_type, &actual_format, + &nitems, &bytesafter, + &tmpatom) == Success + && tmpatom) { + unsigned char *tmpwindow = NULL; + Atom _NET_VIRTUAL_ROOTS = XInternAtom(display, + "_NET_VIRTUAL_ROOTS", + False); + XFree(tmpatom); + if (XGetWindowProperty(display, root, + _NET_VIRTUAL_ROOTS, 0, 1, False, + XA_WINDOW, &actual_type, &actual_format, + &nitems, &bytesafter, + &tmpwindow) != Success + || !tmpwindow) { + /* Must be KDE 2.1+ */ + background = *(Window*)newroot; + } + else if (tmpwindow) { + XFree(tmpwindow); + } + } + + if (!background) { + /* Not KDE: assume windows are reparented */ + background = *clientparent = *newroot; + } + XFree((char *) newroot); + } + else background = __ToonGetKDEDesktop(display, screen, children[i], + _NET_WM_WINDOW_TYPE, + "_NET_WM_WINDOW_TYPE_DESKTOP", + 0); + } + XFree((char *) children); + } + + if (!background) { + /* Look for a _WIN_WORKSPACE property, used by Enlightenment */ + Atom _WIN_WORKSPACE = XInternAtom(display, "_WIN_WORKSPACE", False); + if (XGetWindowProperty(display, root, _WIN_WORKSPACE, + 0, 1, False, XA_CARDINAL, + &actual_type, &actual_format, + &nitems, &bytesafter, + &workspace) == Success + && workspace) { + /* Found a _WIN_WORKSPACE property - this is the desktop to look for. + * For now assume that this is Enlightenment. + * We're looking for a child of the root window that has an + * ENLIGHTENMENT_DESKTOP atom with a value equal to the root window's + * _WIN_WORKSPACE atom. */ + Atom ENLIGHTENMENT_DESKTOP = XInternAtom(display, + "ENLIGHTENMENT_DESKTOP", + False); + /* First check to see if the root window is the current desktop... */ + if (XGetWindowProperty(display, root, + ENLIGHTENMENT_DESKTOP, 0, 1, + False, XA_CARDINAL, + &actual_type, &actual_format, + &nitems, &bytesafter, + &desktop) == Success + && desktop && *desktop == *workspace) { + /* The root window is the current Enlightenment desktop */ + background = root; + XFree(desktop); + } + /* Now look at each immediate child window of root to see if it is + * the current desktop */ + else if (XQueryTree(display, root, &rootReturn, &parentReturn, + &children, &nChildren)) { + int i; + for (i = 0; i < nChildren; ++i) { + if (XGetWindowProperty(display, children[i], + ENLIGHTENMENT_DESKTOP, 0, 1, + False, XA_CARDINAL, + &actual_type, &actual_format, + &nitems, &bytesafter, + &desktop) == Success + && desktop && *desktop == *workspace) { + /* Found current Enlightenment desktop */ + background = *clientparent = children[i]; + XFree(desktop); + } + } + XFree((char *) children); + } + XFree(workspace); + } + } + if (background) { + return background; + } + else { + return root; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/rootvis.c Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,456 @@ +#include <string.h> +#include <math.h> +#include <pthread.h> +#include <time.h> + +#include "rootvis.h" +// as imlib2 uses X definitions, it has to be included after the X includes, which are done in rootvis.h +#include <Imlib2.h> +#include "config.h" + +extern Window ToonGetRootWindow(Display*, int, Window*); + +// Forward declarations +static void rootvis_init(void); +static void rootvis_cleanup(void); +static void rootvis_about(void); +static void rootvis_configure(void); +static void rootvis_playback_start(void); +static void rootvis_playback_stop(void); +static void rootvis_render_freq(gint16 freq_data[2][256]); + +// Callback functions +VisPlugin rootvis_vtable = { + 0, // Handle, filled in by xmms + 0, // Filename, filled in by xmms + + 0, // Session ID + "Root Spectrum Analyzer 0.0.8", // description + + 0, // # of PCM channels for render_pcm() + 2, // # of freq channels wanted for render_freq() + + rootvis_init, // Called when plugin is enabled + rootvis_cleanup, // Called when plugin is disabled + NULL,//rootvis_about, // Show the about box + rootvis_configure, // Show the configure box + 0, // Called to disable plugin, filled in by xmms + rootvis_playback_start, // Called when playback starts + rootvis_playback_stop, // Called when playback stops + 0, // Render the PCM data, must return quickly + rootvis_render_freq // Render the freq data, must return quickly +}; + +// XMMS entry point +VisPlugin *get_vplugin_info(void) { + return &rootvis_vtable; +} + +// X related +struct rootvis_x { + int screen; + Display *display; + Window rootWin, Parent; + Pixmap rootBg; + GC gc; + + Visual *vis; + Colormap cm; + Imlib_Image background; + Imlib_Image buffer; +}; + +// thread talk + +struct rootvis_threads { + gint16 freq_data[2][256]; + pthread_t worker[2]; + pthread_mutex_t mutex1; + enum {GO, STOP} control; + char dirty; + /*** dirty flaglist *** + 1: channel 1 geometry change + 2: channel 1 color change + 4: channel 2 geometry change + 8: channel 2 color change + 16: no data yet (don't do anything) + 32: switch mono/stereo + */ +} threads; + +// For use in config_backend: + +void threads_lock(void) { + print_status("Locking"); + pthread_mutex_lock(&threads.mutex1); +} + +void threads_unlock(char dirty) { + print_status("Unlocking"); + threads.dirty = threads.dirty & dirty; + pthread_mutex_unlock(&threads.mutex1); +} + +// Some helper stuff + +void clean_data(void) { + pthread_mutex_lock(&threads.mutex1); + memset(threads.freq_data, 0, sizeof(gint16) * 2 * 256); + pthread_mutex_unlock(&threads.mutex1); +} + +void print_status(char msg[]) { + if (conf.debug == 1) printf(">> rootvis >> %s\n", msg); // for debug purposes, but doesn't tell much anyway +} + +void error_exit(char msg[]) { + printf("*** ERROR (rootvis): %s\n", msg); + rootvis_vtable.disable_plugin(&rootvis_vtable); +} + +void initialize_X(struct rootvis_x* drw, char* display) { + print_status("Opening X Display"); + drw->display = XOpenDisplay(display); + if (drw->display == NULL) { + fprintf(stderr, "cannot connect to X server %s\n", + getenv("DISPLAY") ? getenv("DISPLAY") : "(default)"); + error_exit("Connecting to X server failed"); + pthread_exit(NULL); + } + print_status("Getting screen and window"); + drw->screen = DefaultScreen(drw->display); + drw->rootWin = ToonGetRootWindow(drw->display, drw->screen, &drw->Parent); + + print_status("Initializing Imlib2"); + + drw->vis = DefaultVisual(drw->display, drw->screen); + drw->cm = DefaultColormap(drw->display, drw->screen); + + imlib_context_set_display(drw->display); + imlib_context_set_visual(drw->vis); + imlib_context_set_colormap(drw->cm); + + imlib_context_set_dither(0); + imlib_context_set_blend(1); +} + +void draw_init(struct rootvis_x* drw, unsigned short damage_coords[4]) +{ + Atom tmp_rootmapid, tmp_type; + int tmp_format; + unsigned long tmp_length, tmp_after; + unsigned char *data = NULL; + + if ((tmp_rootmapid = XInternAtom(drw->display, "_XROOTPMAP_ID", True)) != None) + { + int ret = XGetWindowProperty(drw->display, drw->rootWin, tmp_rootmapid, 0L, 1L, False, AnyPropertyType, + &tmp_type, &tmp_format, &tmp_length, &tmp_after,&data); + if ((ret == Success)&&(tmp_type == XA_PIXMAP)&&((drw->rootBg = *((Pixmap *)data)) != None)) { + pthread_mutex_lock(&threads.mutex1); + imlib_context_set_drawable(drw->rootBg); + drw->background = imlib_create_image_from_drawable(0, damage_coords[0], damage_coords[1], damage_coords[2], damage_coords[3], 1); + pthread_mutex_unlock(&threads.mutex1); + } + if (drw->background == NULL) + error_exit("Initial image could not be created"); + } +} + +void draw_close(struct rootvis_x* drw, unsigned short damage_coords[4]) { + pthread_mutex_lock(&threads.mutex1); + imlib_context_set_image(drw->background); + imlib_render_image_on_drawable(damage_coords[0], damage_coords[1]); + XClearArea(drw->display, drw->rootWin, damage_coords[0], damage_coords[1], damage_coords[2], damage_coords[3], True); + imlib_free_image(); + pthread_mutex_unlock(&threads.mutex1); +} + +void draw_start(struct rootvis_x* drw, unsigned short damage_coords[4]) { + imlib_context_set_image(drw->background); + drw->buffer = imlib_clone_image(); + imlib_context_set_image(drw->buffer); +} + +void draw_end(struct rootvis_x* drw, unsigned short damage_coords[4]) { + imlib_context_set_drawable(drw->rootWin); + imlib_render_image_on_drawable(damage_coords[0], damage_coords[1]); + imlib_free_image(); +} + +void draw_bar(struct rootvis_x* drw, int t, int i, unsigned short level, unsigned short oldlevel, unsigned short peak, unsigned short oldpeak) { + + /* to make following cleaner, we work with redundant helper variables + this also avoids some calculations */ + register int a, b, c, d; + float angle; + Imlib_Color_Range range = imlib_create_color_range(); + + if (conf.geo[t].orientation < 2) { + a = i*(conf.bar[t].width + conf.bar[t].shadow + conf.geo[t].space); + c = conf.bar[t].width; + b = d = 0; + } else { + b = (conf.data[t].cutoff/conf.data[t].div - i - 1) + *(conf.bar[t].width + conf.bar[t].shadow + conf.geo[t].space); + d = conf.bar[t].width; + a = c = 0; + } + + if (conf.geo[t].orientation == 0) { b = conf.geo[t].height - level; d = level; } + else if (conf.geo[t].orientation == 1) { b = 0; d = level; } + else if (conf.geo[t].orientation == 2) { a = 0; c = level; } + else { a = conf.geo[t].height - level; c = level; } + + if (conf.bar[t].shadow > 0) { + imlib_context_set_color(conf.bar[t].shadow_color[0], conf.bar[t].shadow_color[1], + conf.bar[t].shadow_color[2], conf.bar[t].shadow_color[3]); + if (conf.bar[t].gradient) + imlib_image_fill_rectangle(a + conf.bar[t].shadow, b + conf.bar[t].shadow, c, d); + else if (conf.bar[t].bevel) + imlib_image_draw_rectangle(a + conf.bar[t].shadow, b + conf.bar[t].shadow, c, d); + + if (conf.peak[t].shadow > 0) + { + int aa = a, bb = b, cc = c, dd = d; + if (conf.geo[t].orientation == 0) { bb = conf.geo[t].height - peak; dd = 1; } + else if (conf.geo[t].orientation == 1) { bb = peak - 1; dd = 1; } + else if (conf.geo[t].orientation == 2) { aa = peak - 1; cc = 1; } + else { aa = conf.geo[t].height - peak; cc = 1; } + imlib_image_fill_rectangle(aa + conf.bar[t].shadow, bb + conf.bar[t].shadow, cc, dd); + } + } + + if (conf.bar[t].gradient) + { + switch (conf.geo[t].orientation) { + case 0: angle = 0.0; break; + case 1: angle = 180.0; break; + case 2: angle = 90.0; break; + case 3: default: + angle = -90.0; + } + + imlib_context_set_color_range(range); + imlib_context_set_color(conf.bar[t].color[3][0], conf.bar[t].color[3][1], conf.bar[t].color[3][2], conf.bar[t].color[3][3]); + imlib_add_color_to_color_range(0); + imlib_context_set_color(conf.bar[t].color[2][0], conf.bar[t].color[2][1], conf.bar[t].color[2][2], conf.bar[t].color[2][3]); + imlib_add_color_to_color_range(level * 2 / 5); + imlib_context_set_color(conf.bar[t].color[1][0], conf.bar[t].color[1][1], conf.bar[t].color[1][2], conf.bar[t].color[1][3]); + imlib_add_color_to_color_range(level * 4 / 5); + imlib_context_set_color(conf.bar[t].color[0][0], conf.bar[t].color[0][1], conf.bar[t].color[0][2], conf.bar[t].color[0][3]); + imlib_add_color_to_color_range(level); + imlib_image_fill_color_range_rectangle(a, b, c, d, angle); + imlib_free_color_range(); + } + + if (conf.bar[t].bevel) + { + imlib_context_set_color(conf.bar[t].bevel_color[0], conf.bar[t].bevel_color[1], + conf.bar[t].bevel_color[2], conf.bar[t].bevel_color[3]); + imlib_image_draw_rectangle(a, b, c, d); + } + + if (peak > 0) { + if (conf.geo[t].orientation == 0) { b = conf.geo[t].height - peak; d = 1; } + else if (conf.geo[t].orientation == 1) { b = peak - 1; d = 1; } + else if (conf.geo[t].orientation == 2) { a = peak - 1; c = 1; } + else { a = conf.geo[t].height - peak; c = 1; } + imlib_context_set_color(conf.peak[t].color[0], conf.peak[t].color[1], conf.peak[t].color[2], conf.peak[t].color[3]); + imlib_image_fill_rectangle(a, b, c, d); + } +} + +// Our worker thread + +void* worker_func(void* threadnump) { + struct rootvis_x draw; + gint16 freq_data[256]; + double scale = 0.0, x00 = 0.0, y00 = 0.0; + unsigned int threadnum, i, j, level; + unsigned short damage_coords[4]; + unsigned short *level1 = NULL, *level2 = NULL, *levelsw, *peak1 = NULL, *peak2 = NULL, *peakstep; + int barcount = 0; + + if (threadnump == NULL) threadnum = 0; else threadnum = 1; + + print_status("Memory allocations"); + level1 = (unsigned short*)calloc(256, sizeof(short)); // need to be zeroed out + level2 = (unsigned short*)malloc(256*sizeof(short)); + peak1 = (unsigned short*)calloc(256, sizeof(short)); // need to be zeroed out + peak2 = (unsigned short*)calloc(256, sizeof(short)); // need to be zeroed out for disabled peaks + peakstep = (unsigned short*)calloc(256, sizeof(short)); // need to be zeroed out + if ((level1 == NULL)||(level2 == NULL)||(peak1 == NULL)||(peak2 == NULL)||(peakstep == NULL)) { + error_exit("Allocation of memory failed"); + pthread_exit(NULL); + } + print_status("Allocations done"); + + draw.display = NULL; + + while (threads.control != STOP) { + + { + //print_status("start sleep"); + struct timespec sleeptime; + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = 999999999 / conf.data[threadnum].fps; + while (nanosleep(&sleeptime, &sleeptime) == -1) {}; //print_status("INTR"); + //print_status("end sleep"); + } + + /* we will unset our own dirty flags after receiving them */ + pthread_mutex_lock(&threads.mutex1); + memcpy(&freq_data, &threads.freq_data[threadnum], sizeof(gint16)*256); + i = threads.dirty; + if ((i & 16) == 0) threads.dirty = i & (~(3 + threadnum*9)); + pthread_mutex_unlock(&threads.mutex1); + + if ((i & 16) == 0) { // we've gotten data + if (draw.display == NULL) initialize_X(&draw, conf.geo[threadnum].display); + else if (i & (1 + threadnum*3)) draw_close(&draw, damage_coords); + + if (i & (1 + threadnum*3)) { // geometry has changed + damage_coords[0] = conf.geo[threadnum].posx; + damage_coords[1] = conf.geo[threadnum].posy; + if (conf.geo[threadnum].orientation < 2) { + damage_coords[2] = conf.data[threadnum].cutoff/conf.data[threadnum].div + *(conf.bar[threadnum].width + conf.bar[threadnum].shadow + conf.geo[threadnum].space); + damage_coords[3] = conf.geo[threadnum].height + conf.bar[threadnum].shadow; + } else { + damage_coords[2] = conf.geo[threadnum].height + conf.bar[threadnum].shadow; + damage_coords[3] = conf.data[threadnum].cutoff/conf.data[threadnum].div + *(conf.bar[threadnum].width + conf.bar[threadnum].shadow + conf.geo[threadnum].space); + } + print_status("Geometry recalculations"); + scale = conf.geo[threadnum].height / + (log((1 - conf.data[threadnum].linearity) / conf.data[threadnum].linearity) * 4); + x00 = conf.data[threadnum].linearity*conf.data[threadnum].linearity*32768.0 / + (2*conf.data[threadnum].linearity - 1); + y00 = -log(-x00) * scale; + barcount = conf.data[threadnum].cutoff/conf.data[threadnum].div; + memset(level1, 0, 256*sizeof(short)); + memset(peak1, 0, 256*sizeof(short)); + memset(peak2, 0, 256*sizeof(short)); + + draw_init(&draw, damage_coords); + } + /*if (i & (2 + threadnum*6)) { // colors have changed + }*/ + + /* instead of copying the old level array to the second array, + we just tell the first is now the second one */ + levelsw = level1; + level1 = level2; + level2 = levelsw; + levelsw = peak1; + peak1 = peak2; + peak2 = levelsw; + + for (i = 0; i < barcount; i++) { + level = 0; + for (j = i*conf.data[threadnum].div; j < (i+1)*conf.data[threadnum].div; j++) + if (level < freq_data[j]) + level = freq_data[j]; + level = level * (i*conf.data[threadnum].div + 1); + level = floor(abs(log(level - x00)*scale + y00)); + if (level < conf.geo[threadnum].height) { + if ((level2[i] > conf.bar[threadnum].falloff)&&(level < level2[i] - conf.bar[threadnum].falloff)) + level1[i] = level2[i] - conf.bar[threadnum].falloff; + else level1[i] = level; + } else level1[i] = conf.geo[threadnum].height; + if (conf.peak[threadnum].enabled) { + if (level1[i] > peak2[i] - conf.peak[threadnum].falloff) { + peak1[i] = level1[i]; + peakstep[i] = 0; + } else if (peakstep[i] == conf.peak[threadnum].step) + if (peak2[i] > conf.peak[threadnum].falloff) + peak1[i] = peak2[i] - conf.peak[threadnum].falloff; + else peak1[i] = 0; + else { + peak1[i] = peak2[i]; + peakstep[i]++; + } + } + } + + pthread_mutex_lock(&threads.mutex1); + draw_start(&draw, damage_coords); + for (i = 0; i < barcount; i++) + draw_bar(&draw, threadnum, i, level1[i], level2[i], peak1[i], peak2[i]); + draw_end(&draw, damage_coords); + pthread_mutex_unlock(&threads.mutex1); + } + } + print_status("Worker thread: Exiting"); + if (draw.display != NULL) { + draw_close(&draw, damage_coords); + XCloseDisplay(draw.display); + } + free(level1); free(level2); free(peak1); free(peak2); free(peakstep); + return NULL; +} + + +// da xmms functions + +static void rootvis_init(void) { + int rc1; + print_status("Initializing"); + pthread_mutex_init(&threads.mutex1, NULL); + threads.control = GO; + clean_data(); + config_init(); + threads.dirty = 31; // this means simply everything has changed and there was no data + if ((rc1 = pthread_create(&threads.worker[0], NULL, worker_func, NULL))) { + fprintf(stderr, "Thread creation failed: %d\n", rc1); + error_exit("Thread creation failed"); + } + if ((conf.stereo)&&(rc1 = pthread_create(&threads.worker[1], NULL, worker_func, &rc1))) { + fprintf(stderr, "Thread creation failed: %d\n", rc1); + error_exit("Thread creation failed"); + } +} + +static void rootvis_cleanup(void) { + print_status("Cleanup... "); + threads.control = STOP; + pthread_join(threads.worker[0], NULL); + if (conf.stereo) pthread_join(threads.worker[1], NULL); + print_status("Clean Exit"); +} + +static void rootvis_about(void) +{ + print_status("About"); +} + +static void rootvis_configure(void) +{ + print_status("Configuration trigger"); + config_init(); + config_show(2); +} + +static void rootvis_playback_start(void) +{ + print_status("Playback starting"); +} + +static void rootvis_playback_stop(void) +{ + clean_data(); +} + +static void rootvis_render_freq(gint16 freq_data[2][256]) { + int channel, bucket; + pthread_mutex_lock(&threads.mutex1); + threads.dirty = threads.dirty & (~(16)); // unset no data yet flag + for (channel = 0; channel < 2; channel++) { + for (bucket = 0; bucket < 256; bucket++) { + if (conf.stereo) threads.freq_data[channel][bucket] = freq_data[channel][bucket]; + else if (channel == 0) threads.freq_data[0][bucket] = freq_data[channel][bucket] / 2; + else threads.freq_data[0][bucket] += freq_data[channel][bucket] / 2; + } + } + pthread_mutex_unlock(&threads.mutex1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rootvis/rootvis.h Mon Mar 26 01:19:26 2007 -0700 @@ -0,0 +1,103 @@ +#include <stdio.h> +#include <stdlib.h> +#include <X11/Xlib.h> +#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 */ +#define DEFAULT_stereo 0 // therefore we don't initialize the second channel with different settings + +#define DEFAULT_geometry_posx 520 +#define DEFAULT_geometry_posy 1 +#define DEFAULT_geometry_orientation 0 // 0 = bottom->up, 1 = top->down, 2 = left->right, 3 = right->left +#define DEFAULT_geometry_height 50 // maximum height/amplitude of a bar +#define DEFAULT_geometry_space 1 // space between bars +#define DEFAULT_bar_width 8 // width of a bar +// set the following to 0 to disable shadows +#define DEFAULT_bar_shadow 1 // offset of shadow in pixels +// set the following to HEIGHT to disable falloff +#define DEFAULT_bar_falloff 5 // how many pixels the bars should falloff every frame +#define DEFAULT_bar_color_1 "#a3c422FF" +#define DEFAULT_bar_color_2 "#b8dd27FF" +#define DEFAULT_bar_color_3 "#cdf62bFF" +#define DEFAULT_bar_color_4 "#e6ff64FF" +#define DEFAULT_bar_shadow_color "#00285088" + +// set the following to 0 to disable peaks +#define DEFAULT_peak_enabled 1 +#define DEFAULT_peak_falloff 4 // how many pixels the peaks should falloff every frame +#define DEFAULT_peak_step 5 // how many frames should the peak resist the falloff +#define DEFAULT_peak_color "#ffffffdd" + +// we're cutting off high frequencies by only showing 0 to CUTOFF +#define DEFAULT_cutoff 180 // frequencies are represented by 256 values +#define DEFAULT_div 4 // we have CUTOFF sources, every bar represents DIV sources + +/* Linearity of the amplitude scale (0.5 for linear, keep in [0.1, 0.9]) */ +#define DEFAULT_linearity 0.33 +#define DEFAULT_fps 30 // how many frames per second should be drawn + +// print out debug messages +#define DEFAULT_debug 0 + +// this is for color[] indexing + +#define RED 0 +#define GREEN 1 +#define BLUE 2 +#define ALPHA 3 +#define COLORSIZE 4 + + +void print_status(char msg[]); +void error_exit(char msg[]); + +void threads_lock(void); +void threads_unlock(char); + +struct rootvis_geometry { + char* display; + int posx; + int posy; + int orientation; + int height; + int space; +}; + +struct rootvis_bar { + int width; + int shadow; + int falloff; + int bevel; + int gradient; + unsigned char color[4][4]; + unsigned char bevel_color[4]; + unsigned char shadow_color[4]; +}; + +struct rootvis_peak { + int enabled; + int falloff; + int step; + int shadow; + unsigned char color[4]; +}; + +struct rootvis_data { + int cutoff; + int div; + int fps; + float linearity; +}; + +struct rootvis_config { + int stereo; + struct rootvis_geometry geo[2]; + struct rootvis_bar bar[2]; + struct rootvis_peak peak[2]; + struct rootvis_data data[2]; + int debug; +} conf;