sinek/src gtkxine.c,1.10,1.11 keys.c,1.44,1.45 main.c,1.24,1.25 prefs.c,1.27,1.28

[email protected] Mon, 20 Jan 2003 20:52:51 -0800
Newsgroups gmane.comp.video.sinek.cvs
Message-ID <[email protected]>
Update of /cvsroot/sinek/sinek/src
In directory sc8-pr-cvs1:/tmp/cvs-serv26818/src

Modified Files:
	gtkxine.c keys.c main.c prefs.c 
Log Message:
prefs cleanup and fixes


Index: gtkxine.c
===================================================================
RCS file: /cvsroot/sinek/sinek/src/gtkxine.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- gtkxine.c	19 Jan 2003 08:35:35 -0000	1.10
+++ gtkxine.c	21 Jan 2003 04:52:49 -0000	1.11
@@ -9,8 +9,6 @@
 */
 
 #include "gtkxine.h"
-#include <gtk/gtk.h>
-#include <xine.h>
 #include <math.h>
 #include <string.h>
 #include <libintl.h>
@@ -351,6 +349,7 @@
 */
 
 #include <X11/Xlib.h>
+#include <X11/extensions/XTest.h>
 #include <X11/extensions/XShm.h>
 #include <gdk/gdkx.h>
 

Index: keys.c
===================================================================
RCS file: /cvsroot/sinek/sinek/src/keys.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- keys.c	16 Jan 2003 07:26:05 -0000	1.44
+++ keys.c	21 Jan 2003 04:52:49 -0000	1.45
@@ -796,7 +796,7 @@
 			break;
 
 		case CMD_SHOW_PREFS:
-			wm_show(prf_build);
+			wm_show(prefs_build);
 			break;
 
 		case CMD_TOGGLE_GUI:

Index: main.c
===================================================================
RCS file: /cvsroot/sinek/sinek/src/main.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- main.c	19 Jan 2003 08:35:35 -0000	1.24
+++ main.c	21 Jan 2003 04:52:49 -0000	1.25
@@ -58,7 +58,7 @@
 		exit(5);
 	}
 
-	prf_init(argc, argv);
+	prefs_init(argc, argv);
 
 	sinek.xine = sinek_init();
 

Index: prefs.c
===================================================================
RCS file: /cvsroot/sinek/sinek/src/prefs.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- prefs.c	19 Jan 2003 08:35:35 -0000	1.27
+++ prefs.c	21 Jan 2003 04:52:49 -0000	1.28
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "gtkxine.h"
+#include <glib/gprintf.h>
 
 #ifdef HAVE_GETOPT_LONG
 #include <getopt.h>
@@ -19,54 +20,96 @@
 {
 	COL_NUM,
 	COL_TITLE,
+	COL_ITEMLIST,
 	N_COLS
 };
 
-static GtkWidget *notebook;
 static GtkTooltips *tips;
-static GList *page_list = NULL;
+static GtkListStore *list_store = NULL;
 
 struct cfgitem
 {
-	char *label;
+	char *label, *full;
 	const void *value;
 	GtkWidget *widget;
-	GList *subitems;
 };
 
-static void print_usage(void);
-static GtkWidget *build_page(GList *items);
-static GtkWidget *build_page_list(void);
+static GtkWidget *build_page(GtkTreeIter *iter);
+static GtkWidget *build_page_list(GtkWidget *notebook);
 static void cb_ok(GtkWidget *w, GtkWidget *win);
 static void cb_apply(GtkWidget *w, gpointer data);
 
-static char *shortopts = "V:A:u:a:D:G:fbgrshv";
+#ifdef USE_GUILE
+static const char *shortopts = "V:A:u:a:G:s:fbgrhv";
+#else
+static const char *shortopts = "V:A:u:a:G:fbgrhv";
+#endif
+
 #ifdef HAVE_GETOPT_LONG
-static struct option longopts[] =
+static const struct option longopts[] =
 {
 	{ "video-driver", required_argument, 0, 'V' },
 	{ "audio-driver", required_argument, 0, 'A' },
 	{ "spu-channel", required_argument, 0, 'u' },
 	{ "audio-channel", required_argument, 0, 'a' },
-	{ "video-display", required_argument, 0, 'D' },
 	{ "geometry", required_argument, 0, 'G' },
+#ifdef USE_GUILE
+	{ "script", required_argument, 0, 's' },
+#endif
 	{ "fullscreen", 0, 0, 'f' },
 	{ "background", 0, 0, 'b' },
 	{ "hide-gui", 0, 0, 'g' },
 	{ "repeat", 0, 0, 'r' },
-	{ "script", required_argument, 0, 's' },
 	{ "help", 0, 0, 'h' },
 	{ "version", 0, 0, 'v' },
 	{ 0, 0, 0, 0 }
 };
 #endif
 
+static void print_version(void)
+{
+	g_print(_("Sinek v%s (Video Player)\n"), VERSION);
+	g_print(_("built with xine library v%d.%d.%d, using v%d.%d.%d.\n"),
+			GTK_XINE_MAJOR_VERSION, GTK_XINE_MINOR_VERSION,
+			GTK_XINE_SUB_VERSION,
+			gtk_xine_get_major_version(GTK_XINE(sinek.xine)),
+			gtk_xine_get_minor_version(GTK_XINE(sinek.xine)),
+			gtk_xine_get_sub_version(GTK_XINE(sinek.xine)));
+}
 
-void prf_init(int argc, char *argv[])
+static void print_usage(int to_stderr)
 {
-	int c, i;
+	FILE *to = to_stderr ? stderr : stdout;
+
+	g_fprintf(to, _("Usage: Sinek [OPTIONS] [MRL]\n"));
+	g_fprintf(to, _("  -V, --video-driver <id>        Select video driver.\n"));
+	g_fprintf(to, _("  -A, --audio-driver <id>        Select audio driver.\n"));
+	g_fprintf(to, _("  -u, --spu-channel <no>         Select SPU subtitle channel.\n"));
+	g_fprintf(to, _("  -a, --audio-channel <no>       Select Audio channel.\n"));
+	g_fprintf(to, _("  -G, --geometry <WxH[+X+Y]>     Set video window coordinates.\n"));
+#ifdef USE_GUILE
+	g_fprintf(to, _("  -s, --script <file>            Execute scheme script.\n"));
+#endif
+	g_fprintf(to, _("  -f, --fullscreen               Start in fullscreen mode.\n"));
+	g_fprintf(to, _("  -b, --background               Play the video in background.\n"));
+	g_fprintf(to, _("  -g, --hide-gui                 Hide control panel.\n"));
+	g_fprintf(to, _("  -r, --repeat                   Play mrl continously.\n"));
+	g_fprintf(to, _("  -h, --help                     Print this help text and exit.\n"));
+	g_fprintf(to, _("  -v, --version                  Print version number and exit.\n"));
+#ifndef HAVE_GETOPT_LONG
+	g_fprintf(to, _("(long options are not supported on your system)\n"));
+#endif
+	g_fprintf(to, _("Report bugs to <[email protected]>.\n"));
+
+	exit(to_stderr);
+}
+
+void prefs_init(int argc, char **argv)
+{
+	int c;
 
 #ifdef HAVE_GETOPT_LONG
+	int i;
 	while((c = getopt_long(argc, argv, shortopts, longopts, &i)) != -1)
 #else
 	while((c = getopt(argc, argv, shortopts)) != -1)
@@ -90,17 +133,13 @@
 				sinek.audio_channel = atoi(optarg);
 				break;
 
-			case 'D':
-				sinek.video_display_name = strdup(optarg);
-				break;
-
 			case 'G':
 				if(sscanf(optarg, "%ix%i+%i+%i", &sinek.geo_w, &sinek.geo_h, &sinek.geo_x, &sinek.geo_y) == 4) break;
 				sinek.geo_x = 0;
 				sinek.geo_y = 0;
 				if(sscanf(optarg, "%ix%i", &sinek.geo_w, &sinek.geo_h) == 2) break;
-				printf(_("Invalid geometry argument '%s'.\n"), optarg);
-				exit(1);
+				g_fprintf(stderr, _("Invalid geometry argument '%s'.\n"), optarg);
+				print_usage(1);
 
 			case 'f':
 				sinek.video_mode = VIDEO_FULLSCREEN;
@@ -118,16 +157,20 @@
 				sinek.repeat_one = -1;
 				break;
 
+#ifdef USE_GUILE
 			case 's':
 				sinek.script = g_strdup(optarg);
 				break;
+#endif
 
 			case 'h':
-				print_usage();
+				print_usage(0);
 
 			case 'v':
 				print_version();
 				exit(0);
+			default:
+				print_usage(1);
 		}
 	}
 
@@ -140,118 +183,75 @@
 	print_version();
 }
 
-
-void print_version(void)
-{
-	printf(_("Sinek v%s (Video Player)\n"), VERSION);
-	printf(_("built with xine library v%d.%d.%d, using v%d.%d.%d.\n"),
-		XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION,
-		gtk_xine_get_major_version(GTK_XINE(sinek.xine)),
-		gtk_xine_get_minor_version(GTK_XINE(sinek.xine)),
-		gtk_xine_get_sub_version(GTK_XINE(sinek.xine)));
-}
-
-
-static void print_usage(void)
-{
-	puts(_("Usage: Sinek [OPTIONS] [MRL]"));
-	puts(_("  -V, --video-driver <id>        Select video driver."));
-	puts(_("  -A, --audio-driver <id>        Select audio driver."));
-	puts(_("  -u, --spu-channel <no>         Select SPU subtitle channel."));
-	puts(_("  -a, --audio-channel <no>       Select Audio channel."));
-	puts(_("  -d, --display <DISPLAY>        X display to use for user interface."));
-	puts(_("  -D, --video-display <DISPLAY>  X display to use for video output."));
-	puts(_("  -G, --geometry <WxH[+X+Y]>     Set video window coordinates."));
-	puts(_("  -f, --fullscreen               Start in fullscreen mode."));
-	puts(_("  -b, --background               Play the video in background."));
-	puts(_("  -g, --hide-gui                 Hide control panel."));
-	puts(_("  -r, --repeat                   Play mrl continously."));
-#ifdef USE_GUILE
-	puts(_("  -s, --script <file>            Execute scheme script."));
-#endif
-	puts(_("  -h, --help                     Print this help text and exit."));
-	puts(_("  -v, --version                  Print version number and exit."));
-#ifndef HAVE_GETOPT_LONG
-	puts(_("(long options are not supported on your system)"));
-#endif
-	puts(_("Report bugs to <[email protected]>."));
-	exit(0);
-}
-
-
-int prf_build(GtkWidget **win)
+int prefs_build(GtkWidget **win)
 {
-	GtkWidget *w, *vb, *hb, *bb, *b;
-	GList *page;
+	GtkWidget *w, *vb, *hb, *bb, *b, *notebook;
+	GtkTreeIter iter;
+	int x;
 
 	w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 	gtk_window_set_title(GTK_WINDOW(w), _("Sinek Settings"));
-	gtk_window_set_wmclass(GTK_WINDOW(w), "settings", "sinek");
 
 	tips = gtk_tooltips_new();
+	notebook = gtk_notebook_new();
+	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
 
+	/* top box; preferences list and options */
 	vb = gtk_vbox_new(FALSE, 0);
-	gtk_widget_show(vb);
 	gtk_container_add(GTK_CONTAINER(w), vb);
 
 	hb = gtk_hbox_new(FALSE, 0);
-	gtk_widget_show(hb);
 	gtk_box_pack_start(GTK_BOX(vb), hb, TRUE, TRUE, 0);
-
-	gtk_box_pack_start(GTK_BOX(hb), build_page_list(), FALSE, TRUE, 0);
-
-	notebook = gtk_notebook_new();
-	gtk_widget_show(notebook);
+	gtk_box_pack_start(GTK_BOX(hb), build_page_list(notebook), FALSE, TRUE, 0);
 	gtk_box_pack_start(GTK_BOX(hb), notebook, TRUE, TRUE, 0);
-	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
-	page = g_list_first(page_list);
-	while(page)
-	{
-		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), build_page(page), NULL);
-		page = g_list_next(page);
+
+	x = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
+	while (x) {
+		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), build_page(&iter), NULL);
+		x = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter);
 	}
 
+	/* bottom box; apply/close/ok */
 	bb = gtk_hbutton_box_new();
-	gtk_widget_show(bb);
 	gtk_box_pack_start(GTK_BOX(vb), bb, FALSE, FALSE, 0);
 	gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_END);
 	gtk_container_set_border_width(GTK_CONTAINER(bb), 5);
 	gtk_box_set_spacing(GTK_BOX(bb), 5);
 
 	b = gtk_button_new_from_stock(GTK_STOCK_APPLY);
-	gtk_widget_show(b);
 	gtk_container_add(GTK_CONTAINER(bb), b);
 	g_signal_connect(G_OBJECT(b), "clicked", G_CALLBACK(cb_apply), NULL);
 
 	b = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-	gtk_widget_show(b);
 	gtk_container_add(GTK_CONTAINER(bb), b);
 	g_signal_connect_swapped(G_OBJECT(b), "clicked", G_CALLBACK(gtk_widget_hide), GTK_OBJECT(w));
 
 	b = gtk_button_new_from_stock(GTK_STOCK_OK);
-	gtk_widget_show(b);
 	gtk_container_add(GTK_CONTAINER(bb), b);
 	g_signal_connect(G_OBJECT(b), "clicked", G_CALLBACK(cb_ok), (gpointer)w);
 
+	gtk_widget_show_all(vb);
+
 	*win = w;
 	return WM_NORMAL;
 }
 
 
-static void prf_apply_changes(void)
+static void prefs_apply_changes(void)
  {
-	GList *page, *item;
 	struct cfgitem *citem;
+	void *val = NULL;
+	GtkTreeIter iter;
+	char *title;
+	GList *list;
+	int x;
 
-	page = g_list_first(page_list);
-	while(page)
-	{
-		item = g_list_first(((struct cfgitem *)page->data)->subitems);
-		while(item)
-		{
-			void *val = NULL;
-			citem = (struct cfgitem *)item->data;
-			switch (gtk_xine_config_get(GTK_XINE(sinek.xine), citem->label, val))
+	x = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
+	while (x) {
+		gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_TITLE, &title, COL_ITEMLIST, &list, -1); /* XXX: free/unref? */
+		while (list) {
+			citem = (struct cfgitem *) list->data;
+			switch (gtk_xine_config_get(GTK_XINE(sinek.xine), citem->full, &val))
 			{
 				case GTK_XINE_CONFIG_TYPE_STRING:
 					val = (char *) gtk_entry_get_text(GTK_ENTRY(citem->widget));
@@ -271,19 +271,20 @@
 				default:
 					break;
 			}
-			gtk_xine_config_set(GTK_XINE(sinek.xine), citem->label, val);
-			item = g_list_next(item);
+/* XXX: segv in xineplug_dmx_sputext.so in 1beta2? */
+if (strcmp("misc.spu_src_encoding", citem->full) && strcmp("misc.spu_dst_encoding", citem->full))
+			gtk_xine_config_set(GTK_XINE(sinek.xine), citem->full, val);
+			list = g_list_next(list);
 		}
-		page = g_list_next(page);
+		x = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter);
 	}
 }
 
-
 static void cb_ok(GtkWidget *w, GtkWidget *win)
 {
 	char *tmp;
 
-	prf_apply_changes();
+	prefs_apply_changes();
 	tmp = g_strconcat(g_get_home_dir(), "/.xine/config", NULL);
 	gtk_xine_config_save(GTK_XINE(sinek.xine), tmp);
 	g_free(tmp);
@@ -293,7 +294,7 @@
 
 static void cb_apply(GtkWidget *w, gpointer data)
 {
-	prf_apply_changes();
+	prefs_apply_changes();
 }
 
 
@@ -345,7 +346,7 @@
 	gtk_widget_show(m);
 	gtk_box_pack_start(GTK_BOX(box), m, FALSE, FALSE, 0);
 
-	gtk_xine_config_get_enums(GTK_XINE(sinek.xine), citem->label, &enums);
+	gtk_xine_config_get_enums(GTK_XINE(sinek.xine), citem->full, &enums);
 	opt = gtk_option_menu_new();
 	gtk_widget_show(opt);
 	m = gtk_menu_new();
@@ -402,7 +403,7 @@
 	gtk_widget_show(lab);
 	gtk_box_pack_start(GTK_BOX(box), lab, FALSE, FALSE, 0);
 
-	gtk_xine_config_get_min_max(GTK_XINE(sinek.xine), citem->label, &min, &max);
+	gtk_xine_config_get_min_max(GTK_XINE(sinek.xine), citem->full, &min, &max);
 	adj = gtk_adjustment_new((int) citem->value, min, max, 1, 0, 0);
 	scale = gtk_hscale_new(GTK_ADJUSTMENT(adj));
 	gtk_widget_show(scale);
@@ -415,11 +416,12 @@
 }
 
 
-static GtkWidget *build_page(GList *page)
+static GtkWidget *build_page(GtkTreeIter *iter)
 {
 	GtkWidget *sw, *box, *w;
 	GList *item;
 	struct cfgitem *citem;
+	char *section;
 
 	sw = gtk_scrolled_window_new(NULL, NULL);
 	gtk_widget_show(sw);
@@ -429,11 +431,12 @@
 	gtk_container_set_border_width(GTK_CONTAINER(box), 10);
 	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), box);
 
-	item = g_list_first(((struct cfgitem *)page->data)->subitems);
+	gtk_tree_model_get(GTK_TREE_MODEL(list_store), iter, COL_TITLE, &section, COL_ITEMLIST, &item, -1); /* XXX: free/unref? */
+
 	while(item)
 	{
 		citem = (struct cfgitem *)item->data;
-		switch (gtk_xine_config_get(GTK_XINE(sinek.xine), citem->label, (void **) &citem->value)) {
+		switch (gtk_xine_config_get(GTK_XINE(sinek.xine), citem->full, (void **) &citem->value)) {
 			case GTK_XINE_CONFIG_TYPE_STRING: w = build_string(citem); break;
 			case GTK_XINE_CONFIG_TYPE_BOOL: w = build_checkbox(citem); break;
 			case GTK_XINE_CONFIG_TYPE_ENUM: w = build_option(citem); break;
@@ -448,8 +451,7 @@
 	return sw;
 }
 
-
-static void cb_page(GtkTreeSelection *sel, gpointer data)
+static void cb_page_change(GtkTreeSelection *sel, gpointer data)
 {
 	GtkTreeModel *model;
 	GtkTreeIter iter;
@@ -458,65 +460,70 @@
 	if(gtk_tree_selection_get_selected(sel, &model, &iter))
 	{
 		gtk_tree_model_get(model, &iter, COL_NUM, &row, -1);
-		gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), row);
+		gtk_notebook_set_current_page(GTK_NOTEBOOK(data), row);
 	}
 }
 
+static gint find_page(GtkListStore *list, const char *label, GtkTreeIter *iter)
+{
+	char *title;
+	int x;
+	
+	x = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), iter);
+	while (x) {
+		gtk_tree_model_get(GTK_TREE_MODEL(list), iter, COL_TITLE, &title, -1); /* XXX: free/unref? */
+		if (strcmp(label, title) == 0)
+			return TRUE;
+		x = gtk_tree_model_iter_next(GTK_TREE_MODEL(list), iter);
+	}
+
+	return FALSE;
+}
 
-static GtkWidget *build_page_list(void)
+static GtkWidget *build_page_list(GtkWidget *notebook)
 {
 	GtkWidget *list_view;
-	GtkListStore *list_store;
 	GtkCellRenderer *cell;
 	GtkTreeViewColumn *col;
 	GtkTreeIter iter;
-	GList *item;
-	struct cfgitem *cpage, *citem;
+	struct cfgitem *citem;
 	const char *key, *nextkey;
 	const void *value;
-	gchar *p;
-	int r, len, num = 0;
+	GList *list;
+	int r, num = 0;
 
-	list_store = gtk_list_store_new(N_COLS, G_TYPE_INT, G_TYPE_STRING);
+	list_store = gtk_list_store_new(N_COLS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_POINTER);
 	list_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
 	cell = gtk_cell_renderer_text_new();
 	col = gtk_tree_view_column_new_with_attributes(_("Category"), cell, "text", COL_TITLE, NULL);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), col);
-	gtk_widget_show(list_view);
 
 	r = gtk_xine_config_get_first(GTK_XINE(sinek.xine), &key, &value);
 	while (r != GTK_XINE_CONFIG_TYPE_NONE) {
-		p = strchr((char *) key, '.');
-		if (p) {
-			len = p - key;
-			cpage = NULL;
-			item = g_list_first(page_list);
-			while(item)
-			{
-				if(strncmp(((struct cfgitem *)item->data)->label, key, len) == 0)
-				{
-					cpage = (struct cfgitem *)item->data;
-					break;
-				}
-				item = g_list_next(item);
-			}
-			if(!cpage)
-			{
-				cpage = g_malloc0(sizeof(struct cfgitem));
-				cpage->label = g_strndup(key, len);
+		citem = g_malloc0(sizeof(struct cfgitem));
+		citem->full = g_strdup(key);
+		citem->label = strchr(citem->full, '.');
+		if (citem->label) {
+			*citem->label++ = '\0';
+			if (find_page(list_store, citem->full, &iter))
+				gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, COL_ITEMLIST, &list, -1);
+			else {
+				/* add a new page */
 				gtk_list_store_append(list_store, &iter);
-				gtk_list_store_set(list_store, &iter, COL_NUM, num, COL_TITLE, (gpointer)cpage->label, -1);
+				gtk_list_store_set(list_store, &iter, COL_NUM, num, COL_TITLE, citem->full, COL_ITEMLIST, NULL, -1);
+				list = NULL;
 				num++;
-				page_list = g_list_append(page_list, (gpointer)cpage);
 			}
-			citem = g_malloc0(sizeof(struct cfgitem));
-			citem->label = g_strdup(key + len + 1);
-			cpage->subitems = g_list_append(cpage->subitems, (gpointer)citem);
+
+			*(citem->label - 1) = '.';
+			list = g_list_append(list, (gpointer) citem);
+			gtk_list_store_set(list_store, &iter, COL_ITEMLIST, list, -1);
 		}
+
 		r = gtk_xine_config_get_next(GTK_XINE(sinek.xine), key, &nextkey, &value);
 		key = nextkey;
 	}
-	g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view))), "changed", G_CALLBACK(cb_page), NULL);
+	g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view))), "changed", G_CALLBACK(cb_page_change), (gpointer) notebook);
 
 	return list_view;
 }




-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com