summaryrefslogtreecommitdiffstats
path: root/src/legacy
diff options
context:
space:
mode:
Diffstat (limited to 'src/legacy')
-rw-r--r--src/legacy/e_date.c215
-rw-r--r--src/legacy/e_date.h15
-rw-r--r--src/legacy/gsm_color_button.c859
-rw-r--r--src/legacy/gsm_color_button.h77
-rw-r--r--src/legacy/meson.build16
-rw-r--r--src/legacy/treeview.c289
-rw-r--r--src/legacy/treeview.h43
7 files changed, 1514 insertions, 0 deletions
diff --git a/src/legacy/e_date.c b/src/legacy/e_date.c
new file mode 100644
index 0000000..2697e89
--- /dev/null
+++ b/src/legacy/e_date.c
@@ -0,0 +1,215 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <string.h>
+
+#include "e_date.h"
+
+/*
+ all this code comes from evolution
+ - e-util.c
+ - message-list.c
+*/
+
+
+static size_t e_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
+{
+#ifdef HAVE_LKSTRFTIME
+ return strftime(s, max, fmt, tm);
+#else
+ char *c, *ffmt, *ff;
+ size_t ret;
+
+ ffmt = g_strdup(fmt);
+ ff = ffmt;
+ while ((c = strstr(ff, "%l")) != NULL) {
+ c[1] = 'I';
+ ff = c;
+ }
+
+ ff = ffmt;
+ while ((c = strstr(ff, "%k")) != NULL) {
+ c[1] = 'H';
+ ff = c;
+ }
+
+ ret = strftime(s, max, ffmt, tm);
+ g_free(ffmt);
+ return ret;
+#endif
+}
+
+
+/**
+ * Function to do a last minute fixup of the AM/PM stuff if the locale
+ * and gettext haven't done it right. Most English speaking countries
+ * except the USA use the 24 hour clock (UK, Australia etc). However
+ * since they are English nobody bothers to write a language
+ * translation (gettext) file. So the locale turns off the AM/PM, but
+ * gettext does not turn on the 24 hour clock. Leaving a mess.
+ *
+ * This routine checks if AM/PM are defined in the locale, if not it
+ * forces the use of the 24 hour clock.
+ *
+ * The function itself is a front end on strftime and takes exactly
+ * the same arguments.
+ *
+ * TODO: Actually remove the '%p' from the fixed up string so that
+ * there isn't a stray space.
+ **/
+
+static size_t e_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct tm *tm)
+{
+ char buf[10];
+ char *sp;
+ char *ffmt;
+ size_t ret;
+
+ if (strstr(fmt, "%p")==NULL && strstr(fmt, "%P")==NULL) {
+ /* No AM/PM involved - can use the fmt string directly */
+ ret=e_strftime(s, max, fmt, tm);
+ } else {
+ /* Get the AM/PM symbol from the locale */
+ e_strftime (buf, 10, "%p", tm);
+
+ if (buf[0]) {
+ /**
+ * AM/PM have been defined in the locale
+ * so we can use the fmt string directly
+ **/
+ ret=e_strftime(s, max, fmt, tm);
+ } else {
+ /**
+ * No AM/PM defined by locale
+ * must change to 24 hour clock
+ **/
+ ffmt=g_strdup(fmt);
+ for (sp=ffmt; (sp=strstr(sp, "%l")); sp++) {
+ /**
+ * Maybe this should be 'k', but I have never
+ * seen a 24 clock actually use that format
+ **/
+ sp[1]='H';
+ }
+ for (sp=ffmt; (sp=strstr(sp, "%I")); sp++) {
+ sp[1]='H';
+ }
+ ret=e_strftime(s, max, ffmt, tm);
+ g_free(ffmt);
+ }
+ }
+ return(ret);
+}
+
+static size_t
+e_utf8_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct tm *tm)
+{
+ size_t sz, ret;
+ char *locale_fmt, *buf;
+
+ locale_fmt = g_locale_from_utf8(fmt, -1, NULL, &sz, NULL);
+ if (!locale_fmt)
+ return 0;
+
+ ret = e_strftime_fix_am_pm(s, max, locale_fmt, tm);
+ if (!ret) {
+ g_free (locale_fmt);
+ return 0;
+ }
+
+ buf = g_locale_to_utf8(s, ret, NULL, &sz, NULL);
+ if (!buf) {
+ g_free (locale_fmt);
+ return 0;
+ }
+
+ if (sz >= max) {
+ char *tmp = buf + max - 1;
+ tmp = g_utf8_find_prev_char(buf, tmp);
+ if (tmp)
+ sz = tmp - buf;
+ else
+ sz = 0;
+ }
+ memcpy(s, buf, sz);
+ s[sz] = '\0';
+ g_free(locale_fmt);
+ g_free(buf);
+ return sz;
+}
+
+
+static char *
+filter_date (time_t date)
+{
+ time_t nowdate = time(NULL);
+ time_t yesdate;
+ struct tm then, now, yesterday;
+ char buf[26];
+ gboolean done = FALSE;
+
+ if (date == 0)
+ // xgettext: ? stands for unknown
+ return g_strdup (_("?"));
+
+ localtime_r (&date, &then);
+ localtime_r (&nowdate, &now);
+ if (then.tm_mday == now.tm_mday &&
+ then.tm_mon == now.tm_mon &&
+ then.tm_year == now.tm_year) {
+ e_utf8_strftime_fix_am_pm (buf, 26, _("Today %l∶%M %p"), &then);
+ done = TRUE;
+ }
+ if (!done) {
+ yesdate = nowdate - 60 * 60 * 24;
+ localtime_r (&yesdate, &yesterday);
+ if (then.tm_mday == yesterday.tm_mday &&
+ then.tm_mon == yesterday.tm_mon &&
+ then.tm_year == yesterday.tm_year) {
+ e_utf8_strftime_fix_am_pm (buf, 26, _("Yesterday %l∶%M %p"), &then);
+ done = TRUE;
+ }
+ }
+ if (!done) {
+ int i;
+ for (i = 2; i < 7; i++) {
+ yesdate = nowdate - 60 * 60 * 24 * i;
+ localtime_r (&yesdate, &yesterday);
+ if (then.tm_mday == yesterday.tm_mday &&
+ then.tm_mon == yesterday.tm_mon &&
+ then.tm_year == yesterday.tm_year) {
+ e_utf8_strftime_fix_am_pm (buf, 26, _("%a %l∶%M %p"), &then);
+ done = TRUE;
+ break;
+ }
+ }
+ }
+ if (!done) {
+ if (then.tm_year == now.tm_year) {
+ e_utf8_strftime_fix_am_pm (buf, 26, _("%b %d %l∶%M %p"), &then);
+ } else {
+ e_utf8_strftime_fix_am_pm (buf, 26, _("%b %d %Y"), &then);
+ }
+ }
+#if 0
+#ifdef CTIME_R_THREE_ARGS
+ ctime_r (&date, buf, 26);
+#else
+ ctime_r (&date, buf);
+#endif
+#endif
+
+ return g_strdup (buf);
+}
+
+
+
+
+char *
+procman_format_date_for_display(time_t d)
+{
+ return filter_date(d);
+}
diff --git a/src/legacy/e_date.h b/src/legacy/e_date.h
new file mode 100644
index 0000000..05ab097
--- /dev/null
+++ b/src/legacy/e_date.h
@@ -0,0 +1,15 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+#ifndef _GSM_E_DATE_H_
+#define _GSM_E_DATE_H_
+
+#include <time.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+char *
+procman_format_date_for_display(time_t d);
+
+G_END_DECLS
+
+#endif /* _GSM_E_DATE_H_ */
diff --git a/src/legacy/gsm_color_button.c b/src/legacy/gsm_color_button.c
new file mode 100644
index 0000000..02a8ad3
--- /dev/null
+++ b/src/legacy/gsm_color_button.c
@@ -0,0 +1,859 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Gnome system monitor colour pickers
+ * Copyright (C) 2007 Karl Lattimer <karl@qdh.org.uk>
+ * All rights reserved.
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This software 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 the software; see the file COPYING. If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <librsvg/rsvg.h>
+
+#include "gsm_color_button.h"
+
+typedef struct
+{
+ GtkColorChooserDialog *cc_dialog; /* Color chooser dialog */
+
+ gchar *title; /* Title for the color selection window */
+
+ GdkRGBA color;
+ gdouble fraction; /* Only used by GSMCP_TYPE_PIE */
+ guint type;
+ cairo_surface_t *image_buffer;
+ gdouble highlight;
+ gboolean button_down;
+ gboolean in_button;
+} GsmColorButtonPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsmColorButton, gsm_color_button, GTK_TYPE_DRAWING_AREA);
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_PERCENTAGE,
+ PROP_TITLE,
+ PROP_COLOR,
+ PROP_TYPE,
+};
+
+/* Signals */
+enum
+{
+ COLOR_SET,
+ LAST_SIGNAL
+};
+
+#define GSMCP_MIN_WIDTH 15
+#define GSMCP_MIN_HEIGHT 15
+
+static void gsm_color_button_class_init (GsmColorButtonClass * klass);
+static void gsm_color_button_init (GsmColorButton * color_button);
+static void gsm_color_button_finalize (GObject * object);
+static void gsm_color_button_set_property (GObject * object, guint param_id,
+ const GValue * value,
+ GParamSpec * pspec);
+static void gsm_color_button_get_property (GObject * object, guint param_id,
+ GValue * value,
+ GParamSpec * pspec);
+static gboolean gsm_color_button_draw (GtkWidget *widget,
+ cairo_t *cr);
+static void gsm_color_button_get_preferred_width (GtkWidget * widget,
+ gint * minimum,
+ gint * natural);
+static void gsm_color_button_get_preferred_height (GtkWidget * widget,
+ gint * minimum,
+ gint * natural);
+static gint gsm_color_button_pressed (GtkWidget * widget,
+ GdkEventButton * event);
+static gint gsm_color_button_released (GtkWidget * widget,
+ GdkEventButton * event);
+static gboolean gsm_color_button_enter_notify (GtkWidget * widget,
+ GdkEventCrossing * event);
+static gboolean gsm_color_button_leave_notify (GtkWidget * widget,
+ GdkEventCrossing * event);
+/* source side drag signals */
+static void gsm_color_button_drag_begin (GtkWidget * widget,
+ GdkDragContext * context,
+ gpointer data);
+static void gsm_color_button_drag_data_get (GtkWidget * widget,
+ GdkDragContext * context,
+ GtkSelectionData * selection_data,
+ guint info, guint time,
+ GsmColorButton * color_button);
+
+/* target side drag signals */
+static void gsm_color_button_drag_data_received (GtkWidget * widget,
+ GdkDragContext * context,
+ gint x,
+ gint y,
+ GtkSelectionData *
+ selection_data, guint info,
+ guint32 time,
+ GsmColorButton *
+ color_button);
+
+
+static guint color_button_signals[LAST_SIGNAL] = { 0 };
+
+static const GtkTargetEntry drop_types[] = { {"application/x-color", 0, 0} };
+
+static void
+gsm_color_button_class_init (GsmColorButtonClass * klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *widget_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->get_property = gsm_color_button_get_property;
+ gobject_class->set_property = gsm_color_button_set_property;
+ gobject_class->finalize = gsm_color_button_finalize;
+ widget_class->draw = gsm_color_button_draw;
+ widget_class->get_preferred_width = gsm_color_button_get_preferred_width;
+ widget_class->get_preferred_height = gsm_color_button_get_preferred_height;
+ widget_class->button_release_event = gsm_color_button_released;
+ widget_class->button_press_event = gsm_color_button_pressed;
+ widget_class->enter_notify_event = gsm_color_button_enter_notify;
+ widget_class->leave_notify_event = gsm_color_button_leave_notify;
+
+ g_object_class_install_property (gobject_class,
+ PROP_PERCENTAGE,
+ g_param_spec_double ("fraction",
+ _("Fraction"),
+ // TRANSLATORS: description of the pie color picker's (mem, swap) filled percentage property
+ _("Percentage full for pie color pickers"),
+ 0, 1, 0.5,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_TITLE,
+ g_param_spec_string ("title",
+ _("Title"),
+ _("The title of the color selection dialog"),
+ _("Pick a Color"),
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_COLOR,
+ g_param_spec_boxed ("color",
+ _("Current Color"),
+ _("The selected color"),
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_TYPE,
+ g_param_spec_uint ("type", _("Type"),
+ _("Type of color picker"),
+ 0, 4, 0,
+ G_PARAM_READWRITE));
+
+ color_button_signals[COLOR_SET] = g_signal_new ("color-set",
+ G_TYPE_FROM_CLASS
+ (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+
+static cairo_surface_t *
+fill_image_buffer_from_resource (cairo_t *cr, const char *path)
+{
+ GBytes *bytes;
+ const guint8 *data;
+ gsize len;
+ GError *error = NULL;
+ RsvgHandle *handle;
+ cairo_surface_t *tmp_surface;
+ cairo_t *tmp_cr;
+
+ bytes = g_resources_lookup_data (path, 0 , NULL);
+ data = g_bytes_get_data (bytes, &len);
+
+ handle = rsvg_handle_new_from_data (data, len, &error);
+
+ if (handle == NULL) {
+ g_warning("rsvg_handle_new_from_data(\"%s\") failed: %s",
+ path, (error ? error->message : "unknown error"));
+ if (error)
+ g_error_free(error);
+ g_bytes_unref(bytes);
+ return NULL;
+ }
+
+ tmp_surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ 32, 32);
+ tmp_cr = cairo_create (tmp_surface);
+ rsvg_handle_render_cairo (handle, tmp_cr);
+ cairo_destroy (tmp_cr);
+ g_object_unref (handle);
+ g_bytes_unref(bytes);
+ return tmp_surface;
+}
+
+static gboolean
+gsm_color_button_draw (GtkWidget *widget, cairo_t * cr)
+{
+ GsmColorButton *color_button = GSM_COLOR_BUTTON (widget);
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+ GdkRGBA *color = gdk_rgba_copy(&priv->color);
+ cairo_path_t *path = NULL;
+ gint width, height;
+ gdouble radius, arc_start, arc_end;
+ gdouble highlight_factor;
+ gboolean sensitive = gtk_widget_get_sensitive (widget);
+
+ if (sensitive && priv->highlight > 0) {
+ highlight_factor = 0.125 * priv->highlight;
+
+ color->red = MIN (1.0, color->red + highlight_factor);
+
+ color->blue = MIN (1.0, color->blue + highlight_factor) ;
+
+ color->green = MIN (1.0, color->green + highlight_factor);
+ } else if (!sensitive) {
+ GtkStyleContext *context = gtk_widget_get_style_context (widget);
+ gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget), color);
+ }
+ gdk_cairo_set_source_rgba (cr, color);
+ gdk_rgba_free(color);
+ width = gdk_window_get_width (gtk_widget_get_window (widget));
+ height = gdk_window_get_height(gtk_widget_get_window (widget));
+
+ switch (priv->type)
+ {
+ case GSMCP_TYPE_CPU:
+ //gtk_widget_set_size_request (widget, GSMCP_MIN_WIDTH, GSMCP_MIN_HEIGHT);
+ cairo_paint (cr);
+ cairo_set_line_width (cr, 1);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
+ cairo_rectangle (cr, 0.5, 0.5, width - 1, height - 1);
+ cairo_stroke (cr);
+ cairo_set_line_width (cr, 1);
+ cairo_set_source_rgba (cr, 1, 1, 1, 0.4);
+ cairo_rectangle (cr, 1.5, 1.5, width - 3, height - 3);
+ cairo_stroke (cr);
+ break;
+ case GSMCP_TYPE_PIE:
+ if (width < 32) // 32px minimum size
+ gtk_widget_set_size_request (widget, 32, 32);
+ if (width < height)
+ radius = width / 2;
+ else
+ radius = height / 2;
+
+ arc_start = -G_PI_2 + 2 * G_PI * priv->fraction;
+ arc_end = -G_PI_2;
+
+ cairo_set_line_width (cr, 1);
+
+ // Draw external stroke and fill
+ if (priv->fraction < 0.01) {
+ cairo_arc (cr, (width / 2) + .5, (height / 2) + .5, 4.5,
+ 0, 2 * G_PI);
+ } else if (priv->fraction > 0.99) {
+ cairo_arc (cr, (width / 2) + .5, (height / 2) + .5, radius - 2.25,
+ 0, 2 * G_PI);
+ } else {
+ cairo_arc_negative (cr, (width / 2) + .5, (height / 2) + .5, radius - 2.25,
+ arc_start, arc_end);
+ cairo_arc_negative (cr, (width / 2) + .5, (height / 2) + .5, 4.5,
+ arc_end, arc_start);
+ cairo_arc_negative (cr, (width / 2) + .5, (height / 2) + .5, radius - 2.25,
+ arc_start, arc_start);
+ }
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.7);
+ cairo_stroke (cr);
+
+ // Draw internal highlight
+ cairo_set_source_rgba (cr, 1, 1, 1, 0.45);
+ cairo_set_line_width (cr, 1);
+
+ if (priv->fraction < 0.03) {
+ cairo_arc (cr, (width / 2) + .5, (height / 2) + .5, 3.25,
+ 0, 2 * G_PI);
+ } else if (priv->fraction > 0.99) {
+ cairo_arc (cr, (width / 2) + .5, (height / 2) + .5, radius - 3.5,
+ 0, 2 * G_PI);
+ } else {
+ cairo_arc_negative (cr, (width / 2) + .5, (height / 2) + .5, radius - 3.5,
+ arc_start + (1 / (radius - 3.75)),
+ arc_end - (1 / (radius - 3.75)));
+ cairo_arc_negative (cr, (width / 2) + .5, (height / 2) + .5, 3.25,
+ arc_end - (1 / (radius - 3.75)),
+ arc_start + (1 / (radius - 3.75)));
+ cairo_arc_negative (cr, (width / 2) + .5, (height / 2) + .5, radius - 3.5,
+ arc_start + (1 / (radius - 3.75)),
+ arc_start + (1 / (radius - 3.75)));
+ }
+ cairo_stroke (cr);
+
+ // Draw external shape
+ cairo_set_line_width (cr, 1);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
+ cairo_arc (cr, (width / 2) + .5, (height / 2) + .5, radius - 1.25, 0,
+ G_PI * 2);
+ cairo_stroke (cr);
+
+ break;
+ case GSMCP_TYPE_NETWORK_IN:
+ if (priv->image_buffer == NULL)
+ priv->image_buffer =
+ fill_image_buffer_from_resource (cr, "/org/gnome/gnome-system-monitor/pixmaps/download.svg");
+ gtk_widget_set_size_request (widget, 32, 32);
+ cairo_move_to (cr, 8.5, 1.5);
+ cairo_line_to (cr, 23.5, 1.5);
+ cairo_line_to (cr, 23.5, 11.5);
+ cairo_line_to (cr, 29.5, 11.5);
+ cairo_line_to (cr, 16.5, 27.5);
+ cairo_line_to (cr, 15.5, 27.5);
+ cairo_line_to (cr, 2.5, 11.5);
+ cairo_line_to (cr, 8.5, 11.5);
+ cairo_line_to (cr, 8.5, 1.5);
+ cairo_close_path (cr);
+ path = cairo_copy_path (cr);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+ cairo_set_line_width (cr, 1);
+ cairo_fill_preserve (cr);
+ cairo_set_miter_limit (cr, 5.0);
+ cairo_stroke (cr);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
+ cairo_append_path (cr, path);
+ cairo_path_destroy(path);
+ cairo_stroke (cr);
+ cairo_set_source_surface (cr, priv->image_buffer, 0.0,
+ 0.0);
+ cairo_paint (cr);
+
+ break;
+ case GSMCP_TYPE_NETWORK_OUT:
+ if (priv->image_buffer == NULL)
+ priv->image_buffer =
+ fill_image_buffer_from_resource (cr, "/org/gnome/gnome-system-monitor/pixmaps/upload.svg");
+ gtk_widget_set_size_request (widget, 32, 32);
+ cairo_move_to (cr, 16.5, 1.5);
+ cairo_line_to (cr, 29.5, 17.5);
+ cairo_line_to (cr, 23.5, 17.5);
+ cairo_line_to (cr, 23.5, 27.5);
+ cairo_line_to (cr, 8.5, 27.5);
+ cairo_line_to (cr, 8.5, 17.5);
+ cairo_line_to (cr, 2.5, 17.5);
+ cairo_line_to (cr, 15.5, 1.5);
+ cairo_line_to (cr, 16.5, 1.5);
+ cairo_close_path (cr);
+ path = cairo_copy_path (cr);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+ cairo_set_line_width (cr, 1);
+ cairo_fill_preserve (cr);
+ cairo_set_miter_limit (cr, 5.0);
+ cairo_stroke (cr);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
+ cairo_append_path (cr, path);
+ cairo_path_destroy(path);
+ cairo_stroke (cr);
+ cairo_set_source_surface (cr, priv->image_buffer, 0.0,
+ 0.0);
+ cairo_paint (cr);
+
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+gsm_color_button_get_preferred_width (GtkWidget * widget,
+ gint * minimum,
+ gint * natural)
+{
+ if (minimum)
+ *minimum = GSMCP_MIN_WIDTH;
+ if (natural)
+ *natural = GSMCP_MIN_WIDTH;
+}
+
+static void
+gsm_color_button_get_preferred_height (GtkWidget * widget,
+ gint * minimum,
+ gint * natural)
+{
+ if (minimum)
+ *minimum = GSMCP_MIN_HEIGHT;
+ if (natural)
+ *natural = GSMCP_MIN_HEIGHT;
+}
+
+static void
+gsm_color_button_drag_data_received (GtkWidget * widget,
+ GdkDragContext * context,
+ gint x,
+ gint y,
+ GtkSelectionData * selection_data,
+ guint info,
+ guint32 time,
+ GsmColorButton * color_button)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+
+ gint length;
+ guint16 *dropped;
+
+ length = gtk_selection_data_get_length (selection_data);
+
+ if (length < 0)
+ return;
+
+ /* We accept drops with the wrong format, since the KDE color
+ * chooser incorrectly drops application/x-color with format 8.
+ */
+ if (length != 8)
+ {
+ g_warning (_("Received invalid color data\n"));
+ return;
+ }
+
+
+ dropped = (guint16 *) gtk_selection_data_get_data (selection_data);
+
+ priv->color.red = (gdouble)dropped[0] / 0xffff;
+ priv->color.green = (gdouble)dropped[1] / 0xffff;
+ priv->color.blue = (gdouble)dropped[2] / 0xffff;
+
+ gtk_widget_queue_draw (GTK_WIDGET (color_button));
+
+ g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
+
+ g_object_freeze_notify (G_OBJECT (color_button));
+ g_object_notify (G_OBJECT (color_button), "color");
+ g_object_thaw_notify (G_OBJECT (color_button));
+}
+
+
+static void
+set_color_icon (GdkDragContext * context, GdkRGBA * color)
+{
+ GdkPixbuf *pixbuf;
+ guint32 pixel;
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 48, 32);
+
+ pixel = ((guint32)(color->red * 0xff) << 24) |
+ ((guint32)(color->green * 0xff) << 16) |
+ ((guint32)(color->blue * 0xff) << 8);
+
+ gdk_pixbuf_fill (pixbuf, pixel);
+
+ gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
+ g_object_unref (pixbuf);
+}
+
+static void
+gsm_color_button_drag_begin (GtkWidget * widget,
+ GdkDragContext * context, gpointer data)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (GSM_COLOR_BUTTON (data));
+ set_color_icon (context, &priv->color);
+}
+
+static void
+gsm_color_button_drag_data_get (GtkWidget * widget,
+ GdkDragContext * context,
+ GtkSelectionData * selection_data,
+ guint info,
+ guint time, GsmColorButton * color_button)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+ guint16 dropped[4];
+
+ dropped[0] = priv->color.red * 0xffff;
+ dropped[1] = priv->color.green * 0xffff;
+ dropped[2] = priv->color.blue * 0xffff;
+ dropped[3] = 65535; // This widget doesn't care about alpha
+
+ gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
+ 16, (guchar *) dropped, 8);
+}
+
+
+static void
+gsm_color_button_init (GsmColorButton * color_button)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+
+ priv->color.red = 0;
+ priv->color.green = 0;
+ priv->color.blue = 0;
+ priv->fraction = 0.5;
+ priv->type = GSMCP_TYPE_CPU;
+ priv->image_buffer = NULL;
+ priv->title = g_strdup (_("Pick a Color")); /* default title */
+ priv->in_button = FALSE;
+ priv->button_down = FALSE;
+
+ gtk_drag_dest_set (GTK_WIDGET (color_button),
+ GTK_DEST_DEFAULT_MOTION |
+ GTK_DEST_DEFAULT_HIGHLIGHT |
+ GTK_DEST_DEFAULT_DROP, drop_types, 1, GDK_ACTION_COPY);
+ gtk_drag_source_set (GTK_WIDGET (color_button),
+ GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+ drop_types, 1, GDK_ACTION_COPY);
+ g_signal_connect (color_button, "drag_begin",
+ G_CALLBACK (gsm_color_button_drag_begin), color_button);
+ g_signal_connect (color_button, "drag_data_received",
+ G_CALLBACK (gsm_color_button_drag_data_received),
+ color_button);
+ g_signal_connect (color_button, "drag_data_get",
+ G_CALLBACK (gsm_color_button_drag_data_get),
+ color_button);
+
+ gtk_widget_add_events (GTK_WIDGET(color_button), GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK);
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET(color_button), _("Click to set graph colors"));
+}
+
+static void
+gsm_color_button_finalize (GObject * object)
+{
+ GsmColorButton *color_button = GSM_COLOR_BUTTON (object);
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+
+ if (priv->cc_dialog != NULL)
+ gtk_widget_destroy (GTK_WIDGET (priv->cc_dialog));
+ priv->cc_dialog = NULL;
+
+ g_free (priv->title);
+ priv->title = NULL;
+
+ cairo_surface_destroy (priv->image_buffer);
+ priv->image_buffer = NULL;
+
+ G_OBJECT_CLASS (gsm_color_button_parent_class)->finalize (object);
+}
+
+GsmColorButton *
+gsm_color_button_new (const GdkRGBA * color, guint type)
+{
+ return g_object_new (GSM_TYPE_COLOR_BUTTON, "color", color, "type", type,
+ "visible", TRUE, NULL);
+}
+
+static void
+dialog_response (GtkWidget * widget, GtkResponseType response, gpointer data)
+{
+ GsmColorButton *color_button = GSM_COLOR_BUTTON (data);
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+ GtkColorChooser *color_chooser;
+
+ if (response == GTK_RESPONSE_OK) {
+ color_chooser = GTK_COLOR_CHOOSER (priv->cc_dialog);
+
+ gtk_color_chooser_get_rgba (color_chooser, &priv->color);
+
+ gtk_widget_hide (GTK_WIDGET (priv->cc_dialog));
+
+ gtk_widget_queue_draw (GTK_WIDGET (color_button));
+
+ g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
+
+ g_object_freeze_notify (G_OBJECT (color_button));
+ g_object_notify (G_OBJECT (color_button), "color");
+ g_object_thaw_notify (G_OBJECT (color_button));
+ }
+ else /* (response == GTK_RESPONSE_CANCEL) */
+ gtk_widget_hide (GTK_WIDGET (priv->cc_dialog));
+}
+
+static gboolean
+dialog_destroy (GtkWidget * widget, gpointer data)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (GSM_COLOR_BUTTON (data));
+
+ priv->cc_dialog = NULL;
+
+ return FALSE;
+}
+
+static gint
+gsm_color_button_clicked (GtkWidget * widget, GdkEventButton * event)
+{
+ GsmColorButton *color_button = GSM_COLOR_BUTTON (widget);
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (color_button);
+
+ /* if dialog already exists, make sure it's shown and raised */
+ if (!priv->cc_dialog)
+ {
+ /* Create the dialog and connects its buttons */
+ GtkColorChooserDialog *cc_dialog;
+ GtkWidget *parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (color_button));
+ if (!gtk_widget_is_toplevel (parent))
+ parent = NULL;
+
+ cc_dialog = GTK_COLOR_CHOOSER_DIALOG (gtk_color_chooser_dialog_new (priv->title, GTK_WINDOW (parent)));
+
+ gtk_window_set_modal (GTK_WINDOW (cc_dialog), TRUE);
+
+ g_signal_connect (cc_dialog, "response",
+ G_CALLBACK (dialog_response), color_button);
+
+ g_signal_connect (cc_dialog, "destroy",
+ G_CALLBACK (dialog_destroy), color_button);
+
+ priv->cc_dialog = cc_dialog;
+ }
+
+ gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (priv->cc_dialog),
+ &priv->color);
+
+ gtk_window_present (GTK_WINDOW (priv->cc_dialog));
+ return 0;
+}
+
+static gint
+gsm_color_button_pressed (GtkWidget * widget, GdkEventButton * event)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (GSM_COLOR_BUTTON (widget));
+
+ if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1))
+ priv->button_down = TRUE;
+ return 0;
+}
+
+static gint
+gsm_color_button_released (GtkWidget * widget, GdkEventButton * event)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (GSM_COLOR_BUTTON (widget));
+ if (priv->button_down && priv->in_button)
+ gsm_color_button_clicked (widget, event);
+ priv->button_down = FALSE;
+ return 0;
+}
+
+
+static gboolean
+gsm_color_button_enter_notify (GtkWidget * widget, GdkEventCrossing * event)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (GSM_COLOR_BUTTON (widget));
+ priv->highlight = 1.0;
+ priv->in_button = TRUE;
+ gtk_widget_queue_draw(widget);
+ return FALSE;
+}
+
+static gboolean
+gsm_color_button_leave_notify (GtkWidget * widget, GdkEventCrossing * event)
+{
+ GsmColorButtonPrivate *priv = gsm_color_button_get_instance_private (GSM_COLOR_BUTTON (widget));
+ priv->highlight = 0;
+ priv->in_button = FALSE;
+ gtk_widget_queue_draw(widget);
+ return FALSE;
+}
+
+guint
+gsm_color_button_get_cbtype (GsmColorButton * color_button)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_val_if_fail (GSM_IS_COLOR_BUTTON (color_button), 0);
+
+ priv = gsm_color_button_get_instance_private (color_button);
+ return priv->type;
+}
+
+void
+gsm_color_button_set_cbtype (GsmColorButton * color_button, guint type)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_if_fail (GSM_IS_COLOR_BUTTON (color_button));
+
+ priv = gsm_color_button_get_instance_private (color_button);
+ priv->type = type;
+
+ gtk_widget_queue_draw (GTK_WIDGET (color_button));
+
+ g_object_notify (G_OBJECT (color_button), "type");
+}
+
+gdouble
+gsm_color_button_get_fraction (GsmColorButton * color_button)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_val_if_fail (GSM_IS_COLOR_BUTTON (color_button), 0);
+
+ priv = gsm_color_button_get_instance_private (color_button);
+ return priv->fraction;
+}
+
+void
+gsm_color_button_set_fraction (GsmColorButton * color_button,
+ gdouble fraction)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_if_fail (GSM_IS_COLOR_BUTTON (color_button));
+
+ priv = gsm_color_button_get_instance_private (color_button);
+
+ priv->fraction = fraction;
+
+ gtk_widget_queue_draw (GTK_WIDGET (color_button));
+
+ g_object_notify (G_OBJECT (color_button), "fraction");
+}
+
+void
+gsm_color_button_get_color (GsmColorButton * color_button, GdkRGBA * color)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_if_fail (GSM_IS_COLOR_BUTTON (color_button));
+
+ priv = gsm_color_button_get_instance_private (color_button);
+
+ color->red = priv->color.red;
+ color->green = priv->color.green;
+ color->blue = priv->color.blue;
+ color->alpha = priv->color.alpha;
+}
+
+void
+gsm_color_button_set_color (GsmColorButton * color_button,
+ const GdkRGBA * color)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_if_fail (GSM_IS_COLOR_BUTTON (color_button));
+ g_return_if_fail (color != NULL);
+
+ priv = gsm_color_button_get_instance_private (color_button);
+
+ priv->color.red = color->red;
+ priv->color.green = color->green;
+ priv->color.blue = color->blue;
+ priv->color.alpha = color->alpha;
+
+ gtk_widget_queue_draw (GTK_WIDGET (color_button));
+
+ g_object_notify (G_OBJECT (color_button), "color");
+}
+
+void
+gsm_color_button_set_title (GsmColorButton * color_button,
+ const gchar * title)
+{
+ GsmColorButtonPrivate *priv;
+ gchar *old_title;
+
+ g_return_if_fail (GSM_IS_COLOR_BUTTON (color_button));
+
+ priv = gsm_color_button_get_instance_private (color_button);
+
+ old_title = priv->title;
+ priv->title = g_strdup (title);
+ g_free (old_title);
+
+ if (priv->cc_dialog)
+ gtk_window_set_title (GTK_WINDOW (priv->cc_dialog),
+ priv->title);
+
+ g_object_notify (G_OBJECT (color_button), "title");
+}
+
+gchar *
+gsm_color_button_get_title (GsmColorButton * color_button)
+{
+ GsmColorButtonPrivate *priv;
+
+ g_return_val_if_fail (GSM_IS_COLOR_BUTTON (color_button), NULL);
+
+ priv = gsm_color_button_get_instance_private (color_button);
+ return priv->title;
+}
+
+static void
+gsm_color_button_set_property (GObject * object,
+ guint param_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GsmColorButton *color_button = GSM_COLOR_BUTTON (object);
+
+ switch (param_id)
+ {
+ case PROP_PERCENTAGE:
+ gsm_color_button_set_fraction (color_button,
+ g_value_get_double (value));
+ break;
+ case PROP_TITLE:
+ gsm_color_button_set_title (color_button, g_value_get_string (value));
+ break;
+ case PROP_COLOR:
+ gsm_color_button_set_color (color_button, g_value_get_boxed (value));
+ break;
+ case PROP_TYPE:
+ gsm_color_button_set_cbtype (color_button, g_value_get_uint (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_color_button_get_property (GObject * object,
+ guint param_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GsmColorButton *color_button = GSM_COLOR_BUTTON (object);
+ GdkRGBA color;
+
+ switch (param_id)
+ {
+ case PROP_PERCENTAGE:
+ g_value_set_double (value,
+ gsm_color_button_get_fraction (color_button));
+ break;
+ case PROP_TITLE:
+ g_value_set_string (value, gsm_color_button_get_title (color_button));
+ break;
+ case PROP_COLOR:
+ gsm_color_button_get_color (color_button, &color);
+ g_value_set_boxed (value, &color);
+ break;
+ case PROP_TYPE:
+ g_value_set_uint (value, gsm_color_button_get_cbtype (color_button));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
diff --git a/src/legacy/gsm_color_button.h b/src/legacy/gsm_color_button.h
new file mode 100644
index 0000000..385dd14
--- /dev/null
+++ b/src/legacy/gsm_color_button.h
@@ -0,0 +1,77 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Gnome system monitor colour pickers
+ * Copyright (C) 2007 Karl Lattimer <karl@qdh.org.uk>
+ * All rights reserved.
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This software 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 the software; see the file COPYING. If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GSM_COLOR_BUTTON_H_
+#define _GSM_COLOR_BUTTON_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/* The GtkColorSelectionButton widget is a simple color picker in a button.
+ * The button displays a sample of the currently selected color. When
+ * the user clicks on the button, a color selection dialog pops up.
+ * The color picker emits the "color_set" signal when the color is set.
+ */
+#define GSM_TYPE_COLOR_BUTTON (gsm_color_button_get_type ())
+#define GSM_COLOR_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_COLOR_BUTTON, GsmColorButton))
+#define GSM_COLOR_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_COLOR_BUTTON, GsmColorButtonClass))
+#define GSM_IS_COLOR_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_COLOR_BUTTON))
+#define GSM_IS_COLOR_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_COLOR_BUTTON))
+#define GSM_COLOR_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_COLOR_BUTTON, GsmColorButtonClass))
+
+typedef struct _GsmColorButton GsmColorButton;
+typedef struct _GsmColorButtonClass GsmColorButtonClass;
+
+struct _GsmColorButton
+{
+ GtkDrawingArea parent_instance;
+};
+
+/* Widget types */
+enum
+{
+ GSMCP_TYPE_CPU,
+ GSMCP_TYPE_PIE,
+ GSMCP_TYPE_NETWORK_IN,
+ GSMCP_TYPE_NETWORK_OUT,
+ GSMCP_TYPES
+};
+
+struct _GsmColorButtonClass
+{
+ GtkDrawingAreaClass parent_class;
+};
+
+GType gsm_color_button_get_type (void);
+GsmColorButton * gsm_color_button_new (const GdkRGBA * color, guint type);
+void gsm_color_button_set_color (GsmColorButton * color_button, const GdkRGBA * color);
+void gsm_color_button_set_fraction (GsmColorButton * color_button, const gdouble fraction);
+void gsm_color_button_set_cbtype (GsmColorButton * color_button, guint type);
+void gsm_color_button_get_color (GsmColorButton * color_button, GdkRGBA * color);
+gdouble gsm_color_button_get_fraction (GsmColorButton * color_button);
+guint gsm_color_button_get_cbtype (GsmColorButton * color_button);
+void gsm_color_button_set_title (GsmColorButton * color_button, const gchar * title);
+gchar * gsm_color_button_get_title (GsmColorButton * color_button);
+
+G_END_DECLS
+
+#endif /* _GSM_COLOR_BUTTON_H_ */
diff --git a/src/legacy/meson.build b/src/legacy/meson.build
new file mode 100644
index 0000000..a66c863
--- /dev/null
+++ b/src/legacy/meson.build
@@ -0,0 +1,16 @@
+
+libgsm_legacy_sources = [
+ 'e_date.c',
+ 'gsm_color_button.c',
+ 'treeview.c',
+]
+
+libgsm_legacy = static_library('gsm_legacy',
+ libgsm_legacy_sources,
+ include_directories: rootInclude,
+ dependencies: [
+ glib,
+ gtk3,
+ librsvg,
+ ],
+)
diff --git a/src/legacy/treeview.c b/src/legacy/treeview.c
new file mode 100644
index 0000000..b50393d
--- /dev/null
+++ b/src/legacy/treeview.c
@@ -0,0 +1,289 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+#include <config.h>
+
+#include "treeview.h"
+
+typedef struct
+{
+ GSettings *settings;
+ gboolean store_column_order;
+ GHashTable *excluded_columns;
+} GsmTreeViewPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsmTreeView, gsm_tree_view, GTK_TYPE_TREE_VIEW)
+
+static void
+gsm_tree_view_finalize (GObject *object)
+{
+ GsmTreeViewPrivate *priv = gsm_tree_view_get_instance_private (GSM_TREE_VIEW (object));
+
+ g_hash_table_destroy (priv->excluded_columns);
+ priv->excluded_columns = NULL;
+
+ G_OBJECT_CLASS (gsm_tree_view_parent_class)->finalize (object);
+}
+
+static void
+gsm_tree_view_class_init (GsmTreeViewClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gsm_tree_view_finalize;
+}
+
+static void
+gsm_tree_view_init (GsmTreeView *self)
+{
+ GsmTreeViewPrivate *priv = gsm_tree_view_get_instance_private (self);
+
+ priv->excluded_columns = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+void
+gsm_tree_view_save_state (GsmTreeView *tree_view)
+{
+ GsmTreeViewPrivate *priv;
+
+ g_return_if_fail (GSM_IS_TREE_VIEW (tree_view));
+
+ priv = gsm_tree_view_get_instance_private (tree_view);
+ GtkTreeModel *model;
+ gint sort_col;
+ GtkSortType sort_type;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ g_settings_delay (priv->settings);
+ if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
+ &sort_col,
+ &sort_type)) {
+ g_settings_set_int (priv->settings, "sort-col", sort_col);
+ g_settings_set_int (priv->settings, "sort-order", sort_type);
+ }
+
+ if (priv->store_column_order) {
+ GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view));
+ GList *iter;
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+
+ for (iter = columns; iter != NULL; iter = iter->next) {
+ gint id = gtk_tree_view_column_get_sort_column_id (GTK_TREE_VIEW_COLUMN (iter->data));
+ g_variant_builder_add (&builder, "i", id);
+ }
+
+ g_settings_set_value (priv->settings, "columns-order",
+ g_variant_builder_end (&builder));
+
+ g_list_free (columns);
+ }
+
+ g_settings_apply (priv->settings);
+}
+
+GtkTreeViewColumn *
+gsm_tree_view_get_column_from_id (GsmTreeView *tree_view, gint sort_id)
+{
+ GList *columns;
+ GList *iter;
+ GtkTreeViewColumn *col = NULL;
+
+ g_return_val_if_fail (GSM_IS_TREE_VIEW (tree_view), NULL);
+
+ columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view));
+
+ for (iter = columns; iter != NULL; iter = iter->next) {
+ col = GTK_TREE_VIEW_COLUMN (iter->data);
+ if (gtk_tree_view_column_get_sort_column_id (col) == sort_id)
+ break;
+ }
+
+ g_list_free (columns);
+
+ return col;
+}
+
+static gboolean
+cb_column_header_clicked (GtkTreeViewColumn *column, GdkEventButton *event, gpointer data)
+{
+ GtkMenu *menu = GTK_MENU (data);
+
+ if (event->button == GDK_BUTTON_SECONDARY) {
+ gtk_menu_popup_at_pointer (menu, (GdkEvent*)event);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+gsm_tree_view_load_state (GsmTreeView *tree_view)
+{
+ GsmTreeViewPrivate *priv;
+ GtkTreeModel *model;
+ gint sort_col;
+ GtkSortType sort_type;
+
+ g_return_if_fail (GSM_IS_TREE_VIEW (tree_view));
+
+ priv = gsm_tree_view_get_instance_private (tree_view);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ sort_col = g_settings_get_int (priv->settings, "sort-col");
+ sort_type = g_settings_get_int (priv->settings, "sort-order");
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ sort_col,
+ sort_type);
+
+ if (priv->store_column_order) {
+ GtkMenu *header_menu = GTK_MENU (gtk_menu_new ());
+ GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view));
+ GList *iter;
+ GVariantIter *var_iter;
+ GtkTreeViewColumn *col, *last;
+ gint sort_id;
+
+ for (iter = columns; iter != NULL; iter = iter->next) {
+ const char *title;
+ char *key;
+ GtkButton *button;
+ GtkCheckMenuItem *column_item;
+
+ col = GTK_TREE_VIEW_COLUMN (iter->data);
+ sort_id = gtk_tree_view_column_get_sort_column_id (col);
+
+ if (priv->excluded_columns &&
+ g_hash_table_contains (priv->excluded_columns, GINT_TO_POINTER (sort_id))) {
+ gtk_tree_view_column_set_visible (col, FALSE);
+ continue;
+ }
+
+ title = gtk_tree_view_column_get_title (col);
+
+ button = GTK_BUTTON (gtk_tree_view_column_get_button (col));
+ g_signal_connect (button, "button-press-event",
+ G_CALLBACK (cb_column_header_clicked),
+ header_menu);
+
+ column_item = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_label (title));
+ g_object_bind_property (col, "visible",
+ column_item, "active",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (header_menu), GTK_WIDGET (column_item));
+
+ key = g_strdup_printf ("col-%d-width", sort_id);
+ gtk_tree_view_column_set_fixed_width (col, g_settings_get_int (priv->settings, key));
+ gtk_tree_view_column_set_min_width (col, 30);
+ g_free (key);
+
+ key = g_strdup_printf ("col-%d-visible", sort_id);
+ gtk_tree_view_column_set_visible (col, g_settings_get_boolean (priv->settings, key));
+ g_free (key);
+ }
+
+ g_list_free (columns);
+
+ gtk_widget_show_all (GTK_WIDGET (header_menu));
+
+ g_settings_get (priv->settings, "columns-order", "ai", &var_iter);
+ last = NULL;
+ while (g_variant_iter_loop (var_iter, "i", &sort_id)) {
+ col = gsm_tree_view_get_column_from_id (tree_view, sort_id);
+
+ if (col != NULL && col != last) {
+ gtk_tree_view_move_column_after (GTK_TREE_VIEW (tree_view),
+ col, last);
+ last = col;
+ }
+ }
+ g_variant_iter_free (var_iter);
+ }
+}
+
+void
+gsm_tree_view_add_excluded_column (GsmTreeView *tree_view, gint column_id)
+{
+ GsmTreeViewPrivate *priv;
+
+ g_return_if_fail (GSM_IS_TREE_VIEW (tree_view));
+
+ priv = gsm_tree_view_get_instance_private (tree_view);
+ g_hash_table_add (priv->excluded_columns, GINT_TO_POINTER (column_id));
+}
+
+static guint timeout_id = 0;
+static GtkTreeViewColumn *current_column;
+
+static gboolean
+save_column_state (gpointer data)
+{
+ GSettings *settings = G_SETTINGS (data);
+ gint column_id = gtk_tree_view_column_get_sort_column_id (current_column);
+ gint width = gtk_tree_view_column_get_width (current_column);
+ gboolean visible = gtk_tree_view_column_get_visible (current_column);
+
+ gchar *key;
+ g_settings_delay (settings);
+
+ key = g_strdup_printf ("col-%d-width", column_id);
+ g_settings_set_int (settings, key, width);
+ g_free (key);
+
+ key = g_strdup_printf ("col-%d-visible", column_id);
+ g_settings_set_boolean (settings, key, visible);
+ g_free (key);
+ timeout_id = 0;
+ g_settings_apply (settings);
+
+ return FALSE;
+}
+
+static void
+cb_update_column_state (GObject *object, GParamSpec *pspec, gpointer data)
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (object);
+
+ current_column = column;
+
+ if (timeout_id > 0)
+ g_source_remove (timeout_id);
+
+ timeout_id = g_timeout_add_seconds (1, save_column_state, data);
+}
+
+void
+gsm_tree_view_append_and_bind_column (GsmTreeView *tree_view, GtkTreeViewColumn *column)
+{
+ GsmTreeViewPrivate *priv;
+
+ g_return_if_fail (GSM_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
+
+ priv = gsm_tree_view_get_instance_private (tree_view);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
+ column);
+
+ g_signal_connect (column, "notify::fixed-width",
+ G_CALLBACK (cb_update_column_state),
+ priv->settings);
+
+ g_signal_connect (column, "notify::visible",
+ G_CALLBACK (cb_update_column_state),
+ priv->settings);
+}
+
+
+GsmTreeView *
+gsm_tree_view_new (GSettings *settings, gboolean store_column_order)
+{
+ GsmTreeView *self = g_object_new (GSM_TYPE_TREE_VIEW, NULL);
+ GsmTreeViewPrivate *priv = gsm_tree_view_get_instance_private (self);
+
+ priv->settings = settings;
+ priv->store_column_order = store_column_order;
+
+ return self;
+}
diff --git a/src/legacy/treeview.h b/src/legacy/treeview.h
new file mode 100644
index 0000000..7223ab1
--- /dev/null
+++ b/src/legacy/treeview.h
@@ -0,0 +1,43 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+#ifndef _GSM_TREE_VIEW_H_
+#define _GSM_TREE_VIEW_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSM_TYPE_TREE_VIEW (gsm_tree_view_get_type ())
+#define GSM_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_TREE_VIEW, GsmTreeView))
+#define GSM_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_TREE_VIEW, GsmTreeViewClass))
+#define GSM_IS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_TREE_VIEW))
+#define GSM_IS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_TREE_VIEW))
+#define GSM_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_TREE_VIEW, GsmTreeViewClass))
+
+typedef struct _GsmTreeView GsmTreeView;
+typedef struct _GsmTreeViewClass GsmTreeViewClass;
+
+struct _GsmTreeView
+{
+ GtkTreeView parent_instance;
+};
+
+struct _GsmTreeViewClass
+{
+ GtkTreeViewClass parent_class;
+};
+
+GType gsm_tree_view_get_type (void) G_GNUC_CONST;
+GsmTreeView * gsm_tree_view_new (GSettings *settings,
+ gboolean store_column_order);
+void gsm_tree_view_save_state (GsmTreeView *tree_view);
+void gsm_tree_view_load_state (GsmTreeView *tree_view);
+GtkTreeViewColumn * gsm_tree_view_get_column_from_id (GsmTreeView *tree_view,
+ gint sort_id);
+void gsm_tree_view_add_excluded_column (GsmTreeView *tree_view,
+ gint column_id);
+void gsm_tree_view_append_and_bind_column (GsmTreeView *tree_view,
+ GtkTreeViewColumn *column);
+
+G_END_DECLS
+
+#endif /* _GSM_TREE_VIEW_H_ */