summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile28
-rw-r--r--src/common.h10
-rw-r--r--src/customcellrendererleft.c127
-rw-r--r--src/customcellrendererleft.h46
-rw-r--r--src/customcellrendererprogress.c139
-rw-r--r--src/customcellrendererprogress.h47
-rw-r--r--src/customcellrendererrate.c129
-rw-r--r--src/customcellrendererrate.h46
-rw-r--r--src/customcellrendererstate.c120
-rw-r--r--src/customcellrendererstate.h53
-rw-r--r--src/main.c166
11 files changed, 911 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..ab842f8
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,28 @@
+CC=gcc
+CFLAGS=-Wall -Wextra -DDEBUG -DHAVE_CONFIG_H -g -I.. -DDATAROOTDIR='"/sw/share/"'
+GTK_CFLAGS=`pkg-config gtk+-2.0 --cflags`
+LDFLAGS=
+GTK_LDFLAGS=`pkg-config gtk+-2.0 --libs`
+
+all: viewtorrents
+
+clean:
+ rm -f *.o viewtorrents
+
+viewtorrents: main.o customcellrendererstate.o customcellrendererprogress.o customcellrendererrate.o customcellrendererleft.o
+ $(CC) $(CFLAGS) $(GTK_CFLAGS) -o $@ $^ $(LDFLAGS) $(GTK_LDFLAGS)
+
+main.o: main.c customcellrendererstate.h customcellrendererprogress.h customcellrendererrate.h customcellrendererleft.h common.h
+ $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
+
+customcellrendererstate.o: customcellrendererstate.c customcellrendererstate.h common.h
+ $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
+
+customcellrendererprogress.o: customcellrendererprogress.c customcellrendererprogress.h common.h
+ $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
+
+customcellrendererrate.o: customcellrendererrate.c customcellrendererrate.h common.h
+ $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
+
+customcellrendererleft.o: customcellrendererleft.c customcellrendererleft.h common.h
+ $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..b5819ac
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,10 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#endif /* COMMON_H */
diff --git a/src/customcellrendererleft.c b/src/customcellrendererleft.c
new file mode 100644
index 0000000..89184e5
--- /dev/null
+++ b/src/customcellrendererleft.c
@@ -0,0 +1,127 @@
+#include "common.h"
+
+#include "customcellrendererleft.h"
+
+static void custom_cell_renderer_left_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec);
+static void custom_cell_renderer_left_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec);
+
+static void convert_left_to_string(gchar* str, guint size, gint64 left);
+
+enum {
+ PROP_0,
+ PROP_LEFT,
+};
+
+G_DEFINE_TYPE(CustomCellRendererLeft, custom_cell_renderer_left, GTK_TYPE_CELL_RENDERER_TEXT)
+
+static void custom_cell_renderer_left_init(CustomCellRendererLeft* cell_left)
+{
+ convert_left_to_string(cell_left->buffer, sizeof(cell_left->buffer),
+ cell_left->left);
+ g_object_set(cell_left, "text", cell_left->buffer, NULL);
+}
+
+static void custom_cell_renderer_left_class_init(CustomCellRendererLeftClass *cell_left_class)
+{
+ GObjectClass *object_class;
+ /* GtkCellRendererClass *cell_renderer_class; */
+
+ object_class = G_OBJECT_CLASS(cell_left_class);
+ /* cell_renderer_class = GTK_CELL_RENDERER_CLASS(cell_left_class); */
+
+ object_class->set_property = custom_cell_renderer_left_set_property;
+ object_class->get_property = custom_cell_renderer_left_get_property;
+
+ g_object_class_install_property(object_class,
+ PROP_LEFT,
+ g_param_spec_int64("left",
+ "Time left",
+ "The time left for the transfer in seconds or -1 if unknown",
+ -1,
+ G_MAXINT64,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+GtkCellRenderer* custom_cell_renderer_left_new(void)
+{
+ return g_object_new(CUSTOM_TYPE_CELL_RENDERER_LEFT, NULL);
+}
+
+void custom_cell_renderer_left_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererLeft* left = CUSTOM_CELL_RENDERER_LEFT(object);
+
+ switch (param_id)
+ {
+ case PROP_LEFT:
+ g_value_set_int64(value, left->left);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+}
+
+void custom_cell_renderer_left_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererLeft* left = CUSTOM_CELL_RENDERER_LEFT(object);
+ gboolean changed = FALSE;
+
+ switch (param_id)
+ {
+ case PROP_LEFT:
+ {
+ gint64 left_value = g_value_get_int64(value);
+
+ if (left->left != left_value)
+ {
+ left->left = left_value;
+ changed = TRUE;
+ }
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+
+ if (changed)
+ {
+ convert_left_to_string(left->buffer, sizeof(left->buffer), left->left);
+ g_object_set(left, "text", left->buffer, NULL);
+ }
+}
+
+void convert_left_to_string(gchar* str, guint size, gint64 left)
+{
+ if (left < 0)
+ {
+ *str = '\0';
+ }
+ else if (left < 60)
+ {
+ g_snprintf(str, size, "%02" G_GINT64_FORMAT "s", left);
+ }
+ else if (left < 60 * 60)
+ {
+ g_snprintf(str, size, "%02" G_GINT64_FORMAT "m%02" G_GINT64_FORMAT "s",
+ left / 60, left % 60);
+ }
+ else
+ {
+ left /= 60;
+ g_snprintf(str, size, "%" G_GINT64_FORMAT "h%02" G_GINT64_FORMAT "m",
+ left / 60, left % 60);
+ }
+}
diff --git a/src/customcellrendererleft.h b/src/customcellrendererleft.h
new file mode 100644
index 0000000..6e18ebd
--- /dev/null
+++ b/src/customcellrendererleft.h
@@ -0,0 +1,46 @@
+#ifndef CUSTOMCELLRENDERERLEFT_H
+#define CUSTOMCELLRENDERERLEFT_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CUSTOM_TYPE_CELL_RENDERER_LEFT \
+ (custom_cell_renderer_left_get_type())
+#define CUSTOM_CELL_RENDERER_LEFT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_LEFT, \
+ CustomCellRendererLeft))
+#define CUSTOM_CELL_RENDERER_LEFT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), CUSTOM_TYPE_CELL_RENDERER_LEFT, \
+ CustomCellRendererLeftClass))
+#define CUSTOM_IS_CELL_RENDERER_LEFT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), CUSTOM_TYPE_CELL_RENDERER_LEFT))
+#define CUSTOM_IS_CELL_RENDERER_LEFT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), CUSTOM_TYPE_CELL_RENDERER_LEFT))
+#define CUSTOM_CELL_RENDERER_LEFT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), CUSTOM_TYPE_CELL_RENDERER_LEFT, \
+ CustomCellRendererLeftClass))
+
+typedef struct _CustomCellRendererLeft CustomCellRendererLeft;
+typedef struct _CustomCellRendererLeftClass CustomCellRendererLeftClass;
+
+struct _CustomCellRendererLeft
+{
+ GtkCellRendererText parent;
+
+ /*< private >*/
+ gint64 GSEAL (left);
+ gchar GSEAL (buffer[20]);
+};
+
+struct _CustomCellRendererLeftClass
+{
+ GtkCellRendererTextClass parent_class;
+};
+
+GType custom_cell_renderer_left_get_type(void) G_GNUC_CONST;
+GtkCellRenderer* custom_cell_renderer_left_new(void);
+
+G_END_DECLS
+
+#endif /* CUSTOMCELLRENDERERLEFT_H */
diff --git a/src/customcellrendererprogress.c b/src/customcellrendererprogress.c
new file mode 100644
index 0000000..04912e7
--- /dev/null
+++ b/src/customcellrendererprogress.c
@@ -0,0 +1,139 @@
+#include "common.h"
+
+#include "customcellrendererprogress.h"
+
+static void custom_cell_renderer_progress_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec);
+static void custom_cell_renderer_progress_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec);
+
+static void update_progress(CustomCellRendererProgress* cell_progress,
+ gfloat downloaded, gfloat seeded);
+
+enum {
+ PROP_0,
+ PROP_DOWNLOADED,
+ PROP_SEEDED,
+};
+
+G_DEFINE_TYPE(CustomCellRendererProgress, custom_cell_renderer_progress, GTK_TYPE_CELL_RENDERER_PROGRESS)
+
+static void custom_cell_renderer_progress_init(CustomCellRendererProgress* cell_progress)
+{
+ update_progress(cell_progress,
+ cell_progress->downloaded, cell_progress->seeded);
+}
+
+static void custom_cell_renderer_progress_class_init(CustomCellRendererProgressClass *cell_progress_class)
+{
+ GObjectClass *object_class;
+ /* GtkCellRendererClass *cell_renderer_class; */
+
+ object_class = G_OBJECT_CLASS(cell_progress_class);
+ /* cell_renderer_class = GTK_CELL_RENDERER_CLASS(cell_progress_class); */
+
+ object_class->set_property = custom_cell_renderer_progress_set_property;
+ object_class->get_property = custom_cell_renderer_progress_get_property;
+
+ g_object_class_install_property(object_class,
+ PROP_DOWNLOADED,
+ g_param_spec_float("downloaded",
+ "Percent downloaded",
+ "Percent of torrent that has been downloaded",
+ 0.0,
+ 100.0,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property(object_class,
+ PROP_SEEDED,
+ g_param_spec_float("seeded",
+ "Seeded ratio",
+ "Seeded ratio",
+ 0.0,
+ G_MAXFLOAT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+GtkCellRenderer* custom_cell_renderer_progress_new(void)
+{
+ return g_object_new(CUSTOM_TYPE_CELL_RENDERER_PROGRESS, NULL);
+}
+
+void custom_cell_renderer_progress_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererProgress* progress = CUSTOM_CELL_RENDERER_PROGRESS(object);
+
+ switch (param_id)
+ {
+ case PROP_DOWNLOADED:
+ g_value_set_float(value, progress->downloaded);
+ break;
+ case PROP_SEEDED:
+ g_value_set_float(value, progress->seeded);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+}
+
+void custom_cell_renderer_progress_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererProgress* progress = CUSTOM_CELL_RENDERER_PROGRESS(object);
+ gboolean changed = FALSE;
+
+ switch (param_id)
+ {
+ case PROP_DOWNLOADED:
+ {
+ gfloat downloaded = g_value_get_float(value);
+
+ if (progress->downloaded != downloaded)
+ {
+ progress->downloaded = downloaded;
+ changed = TRUE;
+ }
+ break;
+ }
+ case PROP_SEEDED:
+ {
+ gfloat seeded = g_value_get_float(value);
+
+ if (progress->seeded != seeded)
+ {
+ progress->seeded = seeded;
+ changed = TRUE;
+ }
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+
+ if (changed)
+ {
+ update_progress(progress, progress->downloaded, progress->seeded);
+ }
+}
+
+void update_progress(CustomCellRendererProgress* cell_progress,
+ gfloat downloaded, gfloat seeded)
+{
+ g_snprintf(cell_progress->buffer, sizeof(cell_progress->buffer),
+ "%2.2f", seeded);
+ g_object_set(cell_progress,
+ "value", (gint)downloaded,
+ "text", cell_progress->buffer,
+ NULL);
+}
diff --git a/src/customcellrendererprogress.h b/src/customcellrendererprogress.h
new file mode 100644
index 0000000..7e3a7ba
--- /dev/null
+++ b/src/customcellrendererprogress.h
@@ -0,0 +1,47 @@
+#ifndef CUSTOMCELLRENDERERPROGRESS_H
+#define CUSTOMCELLRENDERERPROGRESS_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CUSTOM_TYPE_CELL_RENDERER_PROGRESS \
+ (custom_cell_renderer_progress_get_type())
+#define CUSTOM_CELL_RENDERER_PROGRESS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_PROGRESS, \
+ CustomCellRendererProgress))
+#define CUSTOM_CELL_RENDERER_PROGRESS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), CUSTOM_TYPE_CELL_RENDERER_PROGRESS, \
+ CustomCellRendererProgressClass))
+#define CUSTOM_IS_CELL_RENDERER_PROGRESS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), CUSTOM_TYPE_CELL_RENDERER_PROGRESS))
+#define CUSTOM_IS_CELL_RENDERER_PROGRESS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), CUSTOM_TYPE_CELL_RENDERER_PROGRESS))
+#define CUSTOM_CELL_RENDERER_PROGRESS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), CUSTOM_TYPE_CELL_RENDERER_PROGRESS, \
+ CustomCellRendererProgressClass))
+
+typedef struct _CustomCellRendererProgress CustomCellRendererProgress;
+typedef struct _CustomCellRendererProgressClass CustomCellRendererProgressClass;
+
+struct _CustomCellRendererProgress
+{
+ GtkCellRendererProgress parent;
+
+ /*< private >*/
+ gfloat GSEAL (downloaded);
+ gfloat GSEAL (seeded);
+ gchar GSEAL (buffer[10]);
+};
+
+struct _CustomCellRendererProgressClass
+{
+ GtkCellRendererProgressClass parent_class;
+};
+
+GType custom_cell_renderer_progress_get_type(void) G_GNUC_CONST;
+GtkCellRenderer* custom_cell_renderer_progress_new(void);
+
+G_END_DECLS
+
+#endif /* CUSTOMCELLRENDERERPROGRESS_H */
diff --git a/src/customcellrendererrate.c b/src/customcellrendererrate.c
new file mode 100644
index 0000000..4b7b9bf
--- /dev/null
+++ b/src/customcellrendererrate.c
@@ -0,0 +1,129 @@
+#include "common.h"
+
+#include "customcellrendererrate.h"
+
+static void custom_cell_renderer_rate_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec);
+static void custom_cell_renderer_rate_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec);
+
+static void convert_rate_to_string(gchar* str, guint size, gfloat rate);
+
+enum {
+ PROP_0,
+ PROP_RATE,
+};
+
+G_DEFINE_TYPE(CustomCellRendererRate, custom_cell_renderer_rate, GTK_TYPE_CELL_RENDERER_TEXT)
+
+static void custom_cell_renderer_rate_init(CustomCellRendererRate* cell_rate)
+{
+ convert_rate_to_string(cell_rate->buffer, sizeof(cell_rate->buffer),
+ cell_rate->rate);
+ g_object_set(cell_rate, "text", cell_rate->buffer, NULL);
+}
+
+static void custom_cell_renderer_rate_class_init(CustomCellRendererRateClass *cell_rate_class)
+{
+ GObjectClass *object_class;
+ /* GtkCellRendererClass *cell_renderer_class; */
+
+ object_class = G_OBJECT_CLASS(cell_rate_class);
+ /* cell_renderer_class = GTK_CELL_RENDERER_CLASS(cell_rate_class); */
+
+ object_class->set_property = custom_cell_renderer_rate_set_property;
+ object_class->get_property = custom_cell_renderer_rate_get_property;
+
+ g_object_class_install_property(object_class,
+ PROP_RATE,
+ g_param_spec_float("rate",
+ "Rate",
+ "The transfer rate in kilo (1000) byte per second",
+ 0.0,
+ G_MAXFLOAT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+GtkCellRenderer* custom_cell_renderer_rate_new(void)
+{
+ return g_object_new(CUSTOM_TYPE_CELL_RENDERER_RATE, NULL);
+}
+
+void custom_cell_renderer_rate_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererRate* rate = CUSTOM_CELL_RENDERER_RATE(object);
+
+ switch (param_id)
+ {
+ case PROP_RATE:
+ g_value_set_float(value, rate->rate);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+}
+
+void custom_cell_renderer_rate_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererRate* rate = CUSTOM_CELL_RENDERER_RATE(object);
+ gboolean changed = FALSE;
+
+ switch (param_id)
+ {
+ case PROP_RATE:
+ {
+ gfloat rate_value = g_value_get_float(value);
+
+ if (rate->rate != rate_value)
+ {
+ rate->rate = rate_value;
+ changed = TRUE;
+ }
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+
+ if (changed)
+ {
+ convert_rate_to_string(rate->buffer, sizeof(rate->buffer), rate->rate);
+ g_object_set(rate, "text", rate->buffer, NULL);
+ }
+}
+
+void convert_rate_to_string(gchar* str, guint size, gfloat rate)
+{
+ if (rate <= 0.0f)
+ {
+ g_assert(size >= 1);
+ *str = '\0';
+ }
+ else if (rate < 0.9f)
+ {
+ g_snprintf(str, size, "%3fB", rate * 1000.0f);
+ }
+ else if (rate <= 900.0f)
+ {
+ g_snprintf(str, size, "%3.2fkB", rate);
+ }
+ else if (rate <= 900000.0f)
+ {
+ g_snprintf(str, size, "%3.2fMB", rate / 1000.0f);
+ }
+ else
+ {
+ g_snprintf(str, size, "%3.2fGB", rate / 1000000.0f);
+ }
+}
diff --git a/src/customcellrendererrate.h b/src/customcellrendererrate.h
new file mode 100644
index 0000000..48105d3
--- /dev/null
+++ b/src/customcellrendererrate.h
@@ -0,0 +1,46 @@
+#ifndef CUSTOMCELLRENDERERRATE_H
+#define CUSTOMCELLRENDERERRATE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CUSTOM_TYPE_CELL_RENDERER_RATE \
+ (custom_cell_renderer_rate_get_type())
+#define CUSTOM_CELL_RENDERER_RATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_RATE, \
+ CustomCellRendererRate))
+#define CUSTOM_CELL_RENDERER_RATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), CUSTOM_TYPE_CELL_RENDERER_RATE, \
+ CustomCellRendererRateClass))
+#define CUSTOM_IS_CELL_RENDERER_RATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), CUSTOM_TYPE_CELL_RENDERER_RATE))
+#define CUSTOM_IS_CELL_RENDERER_RATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), CUSTOM_TYPE_CELL_RENDERER_RATE))
+#define CUSTOM_CELL_RENDERER_RATE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), CUSTOM_TYPE_CELL_RENDERER_RATE, \
+ CustomCellRendererRateClass))
+
+typedef struct _CustomCellRendererRate CustomCellRendererRate;
+typedef struct _CustomCellRendererRateClass CustomCellRendererRateClass;
+
+struct _CustomCellRendererRate
+{
+ GtkCellRendererText parent;
+
+ /*< private >*/
+ gfloat GSEAL (rate);
+ gchar GSEAL (buffer[10]);
+};
+
+struct _CustomCellRendererRateClass
+{
+ GtkCellRendererTextClass parent_class;
+};
+
+GType custom_cell_renderer_rate_get_type(void) G_GNUC_CONST;
+GtkCellRenderer* custom_cell_renderer_rate_new(void);
+
+G_END_DECLS
+
+#endif /* CUSTOMCELLRENDERERRATE_H */
diff --git a/src/customcellrendererstate.c b/src/customcellrendererstate.c
new file mode 100644
index 0000000..1f0a7f8
--- /dev/null
+++ b/src/customcellrendererstate.c
@@ -0,0 +1,120 @@
+#include "common.h"
+
+#include "customcellrendererstate.h"
+
+static void custom_cell_renderer_state_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec);
+static void custom_cell_renderer_state_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec);
+
+static void update_state(CustomCellRendererState* cell_state, gint state);
+
+enum {
+ PROP_0,
+ PROP_STATE,
+};
+
+G_DEFINE_TYPE(CustomCellRendererState, custom_cell_renderer_state, GTK_TYPE_CELL_RENDERER_PIXBUF)
+
+static void custom_cell_renderer_state_init(CustomCellRendererState* cell_state)
+{
+ update_state(cell_state, cell_state->state);
+}
+
+static void custom_cell_renderer_state_class_init(CustomCellRendererStateClass *cell_state_class)
+{
+ GObjectClass *object_class;
+ /* GtkCellRendererClass *cell_renderer_class; */
+
+ object_class = G_OBJECT_CLASS(cell_state_class);
+ /* cell_renderer_class = GTK_CELL_RENDERER_CLASS(cell_state_class); */
+
+ object_class->set_property = custom_cell_renderer_state_set_property;
+ object_class->get_property = custom_cell_renderer_state_get_property;
+
+ g_object_class_install_property(object_class,
+ PROP_STATE,
+ g_param_spec_int("state",
+ "Torrent state",
+ "Torrent state",
+ STATE_DEAD,
+ STATE_REHASH,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+GtkCellRenderer* custom_cell_renderer_state_new(void)
+{
+ return g_object_new(CUSTOM_TYPE_CELL_RENDERER_STATE, NULL);
+}
+
+void custom_cell_renderer_state_get_property(GObject* object,
+ guint param_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererState* state = CUSTOM_CELL_RENDERER_STATE(object);
+
+ switch (param_id)
+ {
+ case PROP_STATE:
+ g_value_set_int(value, state->state);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+}
+
+void custom_cell_renderer_state_set_property(GObject* object,
+ guint param_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ CustomCellRendererState* state = CUSTOM_CELL_RENDERER_STATE(object);
+ gboolean changed = FALSE;
+
+ switch (param_id)
+ {
+ case PROP_STATE:
+ {
+ gint state_value = g_value_get_int(value);
+
+ if (state->state != state_value)
+ {
+ state->state = state_value;
+ changed = TRUE;
+ }
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+ }
+
+ if (changed)
+ {
+ update_state(state, state->state);
+ }
+}
+
+void update_state(CustomCellRendererState* cell_state, gint state)
+{
+ switch ((state_t)state)
+ {
+ case STATE_DEAD:
+ g_object_set(cell_state, "stock-id", GTK_STOCK_CLOSE, NULL);
+ break;
+ case STATE_ACTIVE:
+ g_object_set(cell_state, "stock-id", GTK_STOCK_YES, NULL);
+ break;
+ case STATE_REHASH:
+ g_object_set(cell_state, "stock-id", GTK_STOCK_REFRESH, NULL);
+ break;
+ default:
+ g_assert(FALSE);
+ break;
+ }
+}
diff --git a/src/customcellrendererstate.h b/src/customcellrendererstate.h
new file mode 100644
index 0000000..3ad16e2
--- /dev/null
+++ b/src/customcellrendererstate.h
@@ -0,0 +1,53 @@
+#ifndef CUSTOMCELLRENDERERSTATE_H
+#define CUSTOMCELLRENDERERSTATE_H
+
+#include <gtk/gtk.h>
+
+typedef enum
+{
+ STATE_DEAD, /* Not active (downloaded >= 100.0 ? closed : paused) */
+ STATE_ACTIVE, /* Active (downloaded >= 100.0 ? seeding : downloading) */
+ STATE_REHASH, /* Hashing */
+} state_t;
+
+G_BEGIN_DECLS
+
+#define CUSTOM_TYPE_CELL_RENDERER_STATE \
+ (custom_cell_renderer_state_get_type())
+#define CUSTOM_CELL_RENDERER_STATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_STATE, \
+ CustomCellRendererState))
+#define CUSTOM_CELL_RENDERER_STATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), CUSTOM_TYPE_CELL_RENDERER_STATE, \
+ CustomCellRendererStateClass))
+#define CUSTOM_IS_CELL_RENDERER_STATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), CUSTOM_TYPE_CELL_RENDERER_STATE))
+#define CUSTOM_IS_CELL_RENDERER_STATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), CUSTOM_TYPE_CELL_RENDERER_STATE))
+#define CUSTOM_CELL_RENDERER_STATE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), CUSTOM_TYPE_CELL_RENDERER_STATE, \
+ CustomCellRendererStateClass))
+
+typedef struct _CustomCellRendererState CustomCellRendererState;
+typedef struct _CustomCellRendererStateClass CustomCellRendererStateClass;
+
+struct _CustomCellRendererState
+{
+ GtkCellRendererPixbuf parent;
+
+ /*< private >*/
+ gint GSEAL (state);
+ GdkPixbuf* GSEAL (buffer[3]);
+};
+
+struct _CustomCellRendererStateClass
+{
+ GtkCellRendererPixbufClass parent_class;
+};
+
+GType custom_cell_renderer_state_get_type(void) G_GNUC_CONST;
+GtkCellRenderer* custom_cell_renderer_state_new(void);
+
+G_END_DECLS
+
+#endif /* CUSTOMCELLRENDERERSTATE_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..3dd9704
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,166 @@
+#include "common.h"
+
+#include <gtk/gtk.h>
+#include "customcellrendererstate.h"
+#include "customcellrendererprogress.h"
+#include "customcellrendererrate.h"
+#include "customcellrendererleft.h"
+#include <string.h>
+
+typedef enum
+{
+ COLUMN_STATE,
+ COLUMN_TITLE,
+ COLUMN_DOWNLOADED,
+ COLUMN_SEEDED,
+ COLUMN_UP,
+ COLUMN_DOWN,
+ COLUMN_LEFT,
+ COLUMN_PROGRESSSORT,
+} column_t;
+
+typedef struct
+{
+ state_t state;
+ gchar* title;
+ gfloat downloaded; /* percent */
+ gfloat seeded; /* ratio */
+ gfloat down, up; /* kilo (1000) byte per second */
+ guint64 size; /* bytes */
+ gint64 left; /* seconds left until done, < 0 means unknown */
+} torrent_t;
+
+static void torrent_update(torrent_t* torrent,
+ GtkListStore* store, GtkTreeIter* iter);
+
+int main(int argc, char** argv)
+{
+ const gchar* gladefile;
+ GtkBuilder* builder;
+ GError* error = NULL;
+ guint ret;
+ GtkWidget* top;
+ GtkWidget* listview;
+ GtkListStore* liststore;
+ GtkTreeIter iter;
+ GtkCellRenderer* cell;
+ GtkTreeViewColumn* column;
+
+ g_thread_init(NULL);
+
+ gtk_init(&argc, &argv);
+
+ builder = gtk_builder_new();
+ gladefile = DATAROOTDIR "viewtorrents/viewtorrents.glade";
+ ret = gtk_builder_add_from_file(builder, gladefile, &error);
+#ifdef DEBUG
+ if (ret == 0)
+ {
+ g_clear_error(&error);
+ gladefile = "gui/viewtorrents.glade";
+ ret = gtk_builder_add_from_file(builder, gladefile, &error);
+ }
+#endif
+ if (ret == 0)
+ {
+ fprintf(stderr, "Unable to load %s: %s\n", gladefile, error->message);
+ g_clear_error(&error);
+ return EXIT_FAILURE;
+ }
+
+ top = GTK_WIDGET(gtk_builder_get_object(builder, "main"));
+
+ g_signal_connect(top, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
+ g_signal_connect(gtk_builder_get_object(builder, "quitmenuitem"),
+ "activate", G_CALLBACK(gtk_main_quit), NULL);
+
+ listview = GTK_WIDGET(gtk_builder_get_object(builder, "treeview"));
+ liststore = GTK_LIST_STORE(gtk_builder_get_object(builder, "liststore"));
+
+ cell = custom_cell_renderer_state_new();
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "statecolumn"));
+ gtk_tree_view_column_pack_start(column, cell, TRUE);
+ gtk_tree_view_column_add_attribute(column, cell, "state", COLUMN_STATE);
+
+ cell = custom_cell_renderer_progress_new();
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "progresscolumn"));
+ gtk_tree_view_column_pack_start(column, cell, TRUE);
+ gtk_tree_view_column_add_attribute(column, cell, "downloaded", COLUMN_DOWNLOADED);
+ gtk_tree_view_column_add_attribute(column, cell, "seeded", COLUMN_SEEDED);
+
+ cell = custom_cell_renderer_rate_new();
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "upcolumn"));
+ gtk_tree_view_column_pack_start(column, cell, TRUE);
+ gtk_tree_view_column_add_attribute(column, cell, "rate", COLUMN_UP);
+
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "downcolumn"));
+ gtk_tree_view_column_pack_start(column, cell, TRUE);
+ gtk_tree_view_column_add_attribute(column, cell, "rate", COLUMN_DOWN);
+
+ cell = custom_cell_renderer_left_new();
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "leftcolumn"));
+ gtk_tree_view_column_pack_start(column, cell, TRUE);
+ gtk_tree_view_column_add_attribute(column, cell, "left", COLUMN_LEFT);
+
+ {
+ torrent_t torrent;
+ torrent.state = STATE_DEAD;
+ torrent.title = "The.Tree.of.Life.2011.720p.BluRay.x264.DTS-HDxT";
+ torrent.seeded = 3.0;
+ torrent.downloaded = 100.0;
+ torrent.up = 0.0;
+ torrent.down = 0.0;
+ torrent.left = -1;
+
+ gtk_list_store_append(liststore, &iter);
+ torrent_update(&torrent, liststore, &iter);
+ }
+ {
+ torrent_t torrent;
+ torrent.state = STATE_ACTIVE;
+ torrent.title = "Burn.Notice.S05E14.720p.HDTV.x264-AVS.mkv";
+ torrent.seeded = 2.79;
+ torrent.downloaded = 100.0;
+ torrent.up = 72.5;
+ torrent.down = 0.0;
+ torrent.left = -1;
+
+ gtk_list_store_append(liststore, &iter);
+ torrent_update(&torrent, liststore, &iter);
+ }
+ {
+ torrent_t torrent;
+ torrent.state = STATE_ACTIVE;
+ torrent.title = "CSI.S12E07.720p.HDTV.X264-DIMENSION.mkv";
+ torrent.seeded = 1.5;
+ torrent.downloaded = 73.45;
+ torrent.up = 37.3;
+ torrent.down = 994.8;
+ torrent.left = 24340;
+
+ gtk_list_store_append(liststore, &iter);
+ torrent_update(&torrent, liststore, &iter);
+ }
+
+ gtk_widget_show_all(top);
+
+ gtk_main();
+
+ return EXIT_SUCCESS;
+}
+
+void torrent_update(torrent_t* torrent, GtkListStore* store, GtkTreeIter* iter)
+{
+ gtk_list_store_set(store, iter,
+ COLUMN_STATE, torrent->state,
+ COLUMN_TITLE, torrent->title,
+ COLUMN_DOWNLOADED, torrent->downloaded,
+ COLUMN_SEEDED, torrent->seeded,
+ COLUMN_UP, torrent->up,
+ COLUMN_DOWN, torrent->down,
+ COLUMN_LEFT, torrent->left,
+ COLUMN_PROGRESSSORT,
+ torrent->downloaded < 100.0f ? torrent->downloaded :
+ torrent->seeded + 1000.0f,
+ -1);
+}