Blame src/load-graph.cpp

Packit 76ec6a
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
Packit 76ec6a
#include <config.h>
Packit 76ec6a
Packit 76ec6a
#include <glib/gi18n.h>
Packit 76ec6a
Packit 76ec6a
#include <glibtop.h>
Packit 76ec6a
#include <glibtop/cpu.h>
Packit 76ec6a
#include <glibtop/mem.h>
Packit 76ec6a
#include <glibtop/swap.h>
Packit 76ec6a
#include <glibtop/netload.h>
Packit 76ec6a
#include <glibtop/netlist.h>
Packit 76ec6a
Packit 76ec6a
#include "application.h"
Packit 76ec6a
#include "load-graph.h"
Packit 76ec6a
#include "util.h"
Packit 76ec6a
#include "legacy/gsm_color_button.h"
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
void LoadGraph::clear_background()
Packit 76ec6a
{
Packit 76ec6a
    if (background) {
Packit 76ec6a
        cairo_surface_destroy (background);
Packit 76ec6a
        background = NULL;
Packit 76ec6a
    }
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
unsigned LoadGraph::num_bars() const
Packit 76ec6a
{
Packit 76ec6a
    unsigned n;
Packit 76ec6a
Packit 76ec6a
    // keep 100 % num_bars == 0
Packit 76ec6a
    switch (static_cast<int>(draw_height / (fontsize + 14)))
Packit 76ec6a
    {
Packit 76ec6a
        case 0:
Packit 76ec6a
        case 1:
Packit 76ec6a
            n = 1;
Packit 76ec6a
            break;
Packit 76ec6a
        case 2:
Packit 76ec6a
        case 3:
Packit 76ec6a
            n = 2;
Packit 76ec6a
            break;
Packit 76ec6a
        case 4:
Packit 76ec6a
            n = 4;
Packit 76ec6a
            break;
Packit 76ec6a
        default:
Packit 76ec6a
            n = 5;
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    return n;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
#define FRAME_WIDTH 4
Packit 76ec6a
void draw_background(LoadGraph *graph) {
Packit 76ec6a
    GtkAllocation allocation;
Packit 76ec6a
    cairo_t *cr;
Packit 76ec6a
    guint i;
Packit 76ec6a
    unsigned num_bars;
Packit 76ec6a
    char *caption;
Packit 76ec6a
    PangoLayout* layout;
Packit 76ec6a
    PangoFontDescription* font_desc;
Packit 76ec6a
    PangoRectangle extents;
Packit 76ec6a
    cairo_surface_t *surface;
Packit 76ec6a
    GdkRGBA fg;
Packit 76ec6a
    GdkRGBA fg_grid;
Packit 76ec6a
    double const border_alpha = 0.7;
Packit 76ec6a
    double const grid_alpha = border_alpha / 2.0;
Packit 76ec6a
Packit 76ec6a
    num_bars = graph->num_bars();
Packit 76ec6a
    graph->graph_dely = (graph->draw_height - 15) / num_bars; /* round to int to avoid AA blur */
Packit 76ec6a
    graph->real_draw_height = graph->graph_dely * num_bars;
Packit 76ec6a
    graph->graph_delx = (graph->draw_width - 2.0 - graph->indent) / (LoadGraph::NUM_POINTS - 3);
Packit 76ec6a
    graph->graph_buffer_offset = (int) (1.5 * graph->graph_delx) + FRAME_WIDTH ;
Packit 76ec6a
Packit 76ec6a
    gtk_widget_get_allocation (GTK_WIDGET (graph->disp), &allocation);
Packit 76ec6a
    surface = gdk_window_create_similar_surface (gtk_widget_get_window (GTK_WIDGET (graph->disp)),
Packit 76ec6a
                                                           CAIRO_CONTENT_COLOR_ALPHA,
Packit 76ec6a
                                                           allocation.width,
Packit 76ec6a
                                                           allocation.height);
Packit 76ec6a
    cr = cairo_create (surface);
Packit 76ec6a
Packit 76ec6a
    GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (GsmApplication::get()->stack));
Packit 76ec6a
    
Packit 76ec6a
    gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg;;
Packit 76ec6a
Packit 76ec6a
    cairo_paint_with_alpha (cr, 0.0);
Packit 76ec6a
    layout = pango_cairo_create_layout (cr);
Packit 76ec6a
    gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
Packit 76ec6a
    pango_font_description_set_size (font_desc, 0.8 * graph->fontsize * PANGO_SCALE);
Packit 76ec6a
    pango_layout_set_font_description (layout, font_desc);
Packit 76ec6a
    pango_font_description_free (font_desc);
Packit 76ec6a
Packit 76ec6a
    /* draw frame */
Packit 76ec6a
    cairo_translate (cr, FRAME_WIDTH, FRAME_WIDTH);
Packit 76ec6a
Packit 76ec6a
    /* Draw background rectangle */
Packit 76ec6a
    /* When a user uses a dark theme, the hard-coded
Packit 76ec6a
     * white background in GSM is a lone white on the
Packit 76ec6a
     * display, which makes the user unhappy. To fix
Packit 76ec6a
     * this, here we offer the user a chance to set
Packit 76ec6a
     * his favorite background color. */
Packit 76ec6a
    gtk_style_context_save (context);
Packit 76ec6a
Packit 76ec6a
    /* Here we specify the name of the class. Now in
Packit 76ec6a
     * the theme's CSS we can specify the own colors
Packit 76ec6a
     * for this class. */
Packit 76ec6a
    gtk_style_context_add_class (context, "loadgraph");
Packit 76ec6a
Packit 76ec6a
    /* And in case the user does not care, we add
Packit 76ec6a
     * classes that usually have a white background. */
Packit 76ec6a
    gtk_style_context_add_class (context, GTK_STYLE_CLASS_PAPER);
Packit 76ec6a
    gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);
Packit 76ec6a
Packit 76ec6a
    /* And, as a bonus, the user can choose the color of the grid. */
Packit 76ec6a
    gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg_grid);
Packit 76ec6a
Packit 76ec6a
    /* Why not use the new features of the
Packit 76ec6a
     * GTK instead of cairo_rectangle ?! :) */
Packit 76ec6a
    gtk_render_background (context, cr, graph->indent, 0.0,
Packit 76ec6a
            graph->draw_width - graph->rmargin - graph->indent,
Packit 76ec6a
            graph->real_draw_height);
Packit 76ec6a
Packit 76ec6a
    gtk_style_context_restore (context);
Packit 76ec6a
Packit 76ec6a
    cairo_set_line_width (cr, 1.0);
Packit 76ec6a
    
Packit 76ec6a
    for (i = 0; i <= num_bars; ++i) {
Packit 76ec6a
        double y;
Packit 76ec6a
Packit 76ec6a
        if (i == 0)
Packit 76ec6a
            y = 0.5 + graph->fontsize / 2.0;
Packit 76ec6a
        else if (i == num_bars)
Packit 76ec6a
            y = i * graph->graph_dely + 0.5;
Packit 76ec6a
        else
Packit 76ec6a
            y = i * graph->graph_dely + graph->fontsize / 2.0;
Packit 76ec6a
Packit 76ec6a
        gdk_cairo_set_source_rgba (cr, &fg;;
Packit 76ec6a
        if (graph->type == LOAD_GRAPH_NET) {
Packit 76ec6a
            // operation orders matters so it's 0 if i == num_bars
Packit 76ec6a
            guint64 rate = graph->net.max - (i * graph->net.max / num_bars);
Packit 76ec6a
            const std::string captionstr(procman::format_network_rate(rate));
Packit 76ec6a
            caption = g_strdup(captionstr.c_str());
Packit 76ec6a
        } else {
Packit 76ec6a
            // operation orders matters so it's 0 if i == num_bars
Packit 76ec6a
            caption = g_strdup_printf("%d %%", 100 - i * (100 / num_bars));
Packit 76ec6a
        }
Packit 76ec6a
        pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
Packit 76ec6a
        pango_layout_set_text (layout, caption, -1);
Packit 76ec6a
        pango_layout_get_extents (layout, NULL, &extents);
Packit 76ec6a
        cairo_move_to (cr, graph->draw_width - graph->indent - 23,
Packit 76ec6a
                       y - 1.0 * extents.height / PANGO_SCALE / 2);
Packit 76ec6a
        pango_cairo_show_layout (cr, layout);
Packit 76ec6a
        g_free(caption);
Packit 76ec6a
Packit 76ec6a
        if (i==0 || i==num_bars)
Packit 76ec6a
            fg_grid.alpha = border_alpha;
Packit 76ec6a
        else
Packit 76ec6a
            fg_grid.alpha = grid_alpha;
Packit 76ec6a
Packit 76ec6a
        gdk_cairo_set_source_rgba (cr, &fg_grid);
Packit 76ec6a
        cairo_move_to (cr, graph->indent, i * graph->graph_dely + 0.5);
Packit 76ec6a
        cairo_line_to (cr, graph->draw_width - graph->rmargin + 0.5 + 4, i * graph->graph_dely + 0.5);
Packit 76ec6a
        cairo_stroke (cr);
Packit 76ec6a
    }
Packit 76ec6a
    
Packit 76ec6a
Packit 76ec6a
    const unsigned total_seconds = graph->speed * (LoadGraph::NUM_POINTS - 2) / 1000;
Packit 76ec6a
Packit 76ec6a
    for (unsigned int i = 0; i < 7; i++) {
Packit 76ec6a
        double x = (i) * (graph->draw_width - graph->rmargin - graph->indent) / 6;
Packit 76ec6a
Packit 76ec6a
        if (i==0 || i==6)
Packit 76ec6a
            fg_grid.alpha = border_alpha;
Packit 76ec6a
        else
Packit 76ec6a
            fg_grid.alpha = grid_alpha;
Packit 76ec6a
Packit 76ec6a
        gdk_cairo_set_source_rgba (cr, &fg_grid);
Packit 76ec6a
        cairo_move_to (cr, (ceil(x) + 0.5) + graph->indent, 0.5);
Packit 76ec6a
        cairo_line_to (cr, (ceil(x) + 0.5) + graph->indent, graph->real_draw_height + 4.5);
Packit 76ec6a
        cairo_stroke(cr);
Packit 76ec6a
        unsigned seconds = total_seconds - i * total_seconds / 6;
Packit 76ec6a
        const char* format;
Packit 76ec6a
        if (i == 0)
Packit 76ec6a
            format = dngettext(GETTEXT_PACKAGE, "%u second", "%u seconds", seconds);
Packit 76ec6a
        else
Packit 76ec6a
            format = "%u";
Packit 76ec6a
        caption = g_strdup_printf(format, seconds);
Packit 76ec6a
        pango_layout_set_text (layout, caption, -1);
Packit 76ec6a
        pango_layout_get_extents (layout, NULL, &extents);
Packit 76ec6a
        cairo_move_to (cr,
Packit 76ec6a
                       (ceil(x) + 0.5 + graph->indent) - (1.0 * extents.width / PANGO_SCALE / 2),
Packit 76ec6a
                       graph->draw_height - 1.0 * extents.height / PANGO_SCALE);
Packit 76ec6a
        gdk_cairo_set_source_rgba (cr, &fg;;
Packit 76ec6a
        pango_cairo_show_layout (cr, layout);
Packit 76ec6a
        g_free (caption);
Packit 76ec6a
    }
Packit 76ec6a
    g_object_unref(layout);
Packit 76ec6a
    cairo_stroke (cr);
Packit 76ec6a
    cairo_destroy (cr);
Packit 76ec6a
    graph->background = surface;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
/* Redraws the backing buffer for the load graph and updates the window */
Packit 76ec6a
void
Packit 76ec6a
load_graph_queue_draw (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    /* repaint */
Packit 76ec6a
    gtk_widget_queue_draw (GTK_WIDGET (graph->disp));
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static int load_graph_update (gpointer user_data); // predeclare load_graph_update so we can compile ;)
Packit 76ec6a
Packit 76ec6a
static gboolean
Packit 76ec6a
load_graph_configure (GtkWidget *widget,
Packit 76ec6a
                      GdkEventConfigure *event,
Packit 76ec6a
                      gpointer data_ptr)
Packit 76ec6a
{
Packit 76ec6a
    GtkAllocation allocation;
Packit 76ec6a
    LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
Packit 76ec6a
Packit 76ec6a
    gtk_widget_get_allocation (widget, &allocation);
Packit 76ec6a
    graph->draw_width = allocation.width - 2 * FRAME_WIDTH;
Packit 76ec6a
    graph->draw_height = allocation.height - 2 * FRAME_WIDTH;
Packit 76ec6a
Packit 76ec6a
    graph->clear_background();
Packit 76ec6a
Packit 76ec6a
    load_graph_queue_draw (graph);
Packit 76ec6a
Packit 76ec6a
    return TRUE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static void force_refresh (LoadGraph * const graph)
Packit 76ec6a
{
Packit 76ec6a
    graph->clear_background();
Packit 76ec6a
    load_graph_queue_draw (graph);
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static void
Packit 76ec6a
load_graph_style_updated (GtkWidget *widget,
Packit 76ec6a
                          gpointer data_ptr)
Packit 76ec6a
{
Packit 76ec6a
    LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
Packit 76ec6a
    force_refresh (graph);
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static gboolean
Packit 76ec6a
load_graph_state_changed (GtkWidget *widget,
Packit 76ec6a
                      GtkStateFlags *flags,
Packit 76ec6a
                      gpointer data_ptr)
Packit 76ec6a
{
Packit 76ec6a
    LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
Packit 76ec6a
    force_refresh (graph);
Packit 76ec6a
    return TRUE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static gboolean
Packit 76ec6a
load_graph_draw (GtkWidget *widget,
Packit 76ec6a
                 cairo_t * cr,
Packit 76ec6a
                 gpointer data_ptr)
Packit 76ec6a
{
Packit 76ec6a
    LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
Packit 76ec6a
Packit 76ec6a
    guint i;
Packit 76ec6a
    gint j;
Packit 76ec6a
    gdouble sample_width, x_offset;
Packit 76ec6a
Packit 76ec6a
    /* Number of pixels wide for one graph point */
Packit 76ec6a
    sample_width = (float)(graph->draw_width - graph->rmargin - graph->indent) / (float)LoadGraph::NUM_POINTS;
Packit 76ec6a
    /* General offset */
Packit 76ec6a
    x_offset = graph->draw_width - graph->rmargin;
Packit 76ec6a
Packit 76ec6a
    /* Subframe offset */
Packit 76ec6a
    x_offset += graph->rmargin - ((sample_width / graph->frames_per_unit) * graph->render_counter);
Packit 76ec6a
Packit 76ec6a
    /* draw the graph */
Packit 76ec6a
Packit 76ec6a
    if (graph->background == NULL) {
Packit 76ec6a
        draw_background(graph);
Packit 76ec6a
    }
Packit 76ec6a
    cairo_set_source_surface (cr, graph->background, 0, 0);
Packit 76ec6a
    cairo_paint (cr);
Packit 76ec6a
Packit 76ec6a
    cairo_set_line_width (cr, 1);
Packit 76ec6a
    cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
Packit 76ec6a
    cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
Packit 76ec6a
    cairo_rectangle (cr, graph->indent + FRAME_WIDTH + 1, FRAME_WIDTH - 1,
Packit 76ec6a
                     graph->draw_width - graph->rmargin - graph->indent - 1,
Packit 76ec6a
                     graph->real_draw_height + FRAME_WIDTH - 1);
Packit 76ec6a
    cairo_clip(cr);
Packit 76ec6a
Packit 76ec6a
    bool drawStacked = graph->type == LOAD_GRAPH_CPU && GsmApplication::get()->config.draw_stacked;
Packit 76ec6a
    bool drawSmooth = graph->type != LOAD_GRAPH_CPU || GsmApplication::get()->config.draw_smooth;
Packit 76ec6a
    for (j = graph->n-1; j >= 0; j--) {
Packit 76ec6a
        gdk_cairo_set_source_rgba (cr, &(graph->colors [j]));
Packit 76ec6a
        if (drawStacked) {
Packit 76ec6a
            cairo_move_to (cr, x_offset, graph->real_draw_height + 3.5f);
Packit 76ec6a
        } else {
Packit 76ec6a
            cairo_move_to (cr, x_offset, (1.0f - graph->data[0][j]) * graph->real_draw_height + 3.5f);
Packit 76ec6a
        }
Packit 76ec6a
        for (i = 1; i < LoadGraph::NUM_POINTS; ++i) {
Packit 76ec6a
            if (graph->data[i][j] == -1.0f)
Packit 76ec6a
                continue;
Packit 76ec6a
            if (drawSmooth) {
Packit 76ec6a
              cairo_curve_to (cr,
Packit 76ec6a
                              x_offset - ((i - 0.5f) * graph->graph_delx),
Packit 76ec6a
                              (1.0 - graph->data[i-1][j]) * graph->real_draw_height + 3.5,
Packit 76ec6a
                              x_offset - ((i - 0.5f) * graph->graph_delx),
Packit 76ec6a
                              (1.0 - graph->data[i][j]) * graph->real_draw_height + 3.5,
Packit 76ec6a
                              x_offset - (i * graph->graph_delx),
Packit 76ec6a
                              (1.0 - graph->data[i][j]) * graph->real_draw_height + 3.5);
Packit 76ec6a
            } else {
Packit 76ec6a
              cairo_line_to (cr, x_offset - (i * graph->graph_delx),
Packit 76ec6a
                              (1.0 - graph->data[i][j]) * graph->real_draw_height + 3.5);
Packit 76ec6a
            }
Packit 76ec6a
Packit 76ec6a
        }
Packit 76ec6a
        if (drawStacked) {
Packit 76ec6a
            cairo_rel_line_to (cr, 0, graph->real_draw_height + 3.5f);
Packit 76ec6a
            //cairo_stroke_preserve(cr);
Packit 76ec6a
            //cairo_close_path(cr);
Packit 76ec6a
            cairo_fill(cr);
Packit 76ec6a
        } else {
Packit 76ec6a
            cairo_stroke (cr);
Packit 76ec6a
        }
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    return TRUE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
void
Packit 76ec6a
load_graph_reset (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    std::fill(graph->data_block.begin(), graph->data_block.end(), -1.0);
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static void
Packit 76ec6a
get_load (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    guint i;
Packit 76ec6a
    glibtop_cpu cpu;
Packit 76ec6a
Packit 76ec6a
    glibtop_get_cpu (&cpu);
Packit 76ec6a
Packit 76ec6a
#undef NOW
Packit 76ec6a
#undef LAST
Packit 76ec6a
#define NOW  (graph->cpu.times[graph->cpu.now])
Packit 76ec6a
#define LAST (graph->cpu.times[graph->cpu.now ^ 1])
Packit 76ec6a
Packit 76ec6a
    if (graph->n == 1) {
Packit 76ec6a
        NOW[0][CPU_TOTAL] = cpu.total;
Packit 76ec6a
        NOW[0][CPU_USED] = cpu.user + cpu.nice + cpu.sys;
Packit 76ec6a
    } else {
Packit 76ec6a
        for (i = 0; i < graph->n; i++) {
Packit 76ec6a
            NOW[i][CPU_TOTAL] = cpu.xcpu_total[i];
Packit 76ec6a
            NOW[i][CPU_USED] = cpu.xcpu_user[i] + cpu.xcpu_nice[i]
Packit 76ec6a
                + cpu.xcpu_sys[i];
Packit 76ec6a
        }
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    // on the first call, LAST is 0
Packit 76ec6a
    // which means data is set to the average load since boot
Packit 76ec6a
    // that value has no meaning, we just want all the
Packit 76ec6a
    // graphs to be aligned, so the CPU graph needs to start
Packit 76ec6a
    // immediately
Packit 76ec6a
    bool drawStacked = graph->type == LOAD_GRAPH_CPU && GsmApplication::get()->config.draw_stacked;
Packit 76ec6a
Packit 76ec6a
    for (i = 0; i < graph->n; i++) {
Packit 76ec6a
        float load;
Packit 76ec6a
        float total, used;
Packit 76ec6a
        gchar *text;
Packit 76ec6a
Packit 76ec6a
        total = NOW[i][CPU_TOTAL] - LAST[i][CPU_TOTAL];
Packit 76ec6a
        used  = NOW[i][CPU_USED]  - LAST[i][CPU_USED];
Packit 76ec6a
Packit 76ec6a
        load = used / MAX(total, 1.0f);
Packit 76ec6a
        graph->data[0][i] = load;
Packit 76ec6a
        if (drawStacked) {
Packit 76ec6a
            graph->data[0][i] /= graph->n;
Packit 76ec6a
            if (i > 0) {
Packit 76ec6a
                graph->data[0][i] += graph->data[0][i-1];
Packit 76ec6a
            }
Packit 76ec6a
        }
Packit 76ec6a
Packit 76ec6a
        /* Update label */
Packit 76ec6a
        text = g_strdup_printf("%.1f%%", load * 100.0f);
Packit 76ec6a
        gtk_label_set_text(GTK_LABEL(graph->labels.cpu[i]), text);
Packit 76ec6a
        g_free(text);
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    graph->cpu.now ^= 1;
Packit 76ec6a
Packit 76ec6a
#undef NOW
Packit 76ec6a
#undef LAST
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
namespace
Packit 76ec6a
{
Packit 76ec6a
Packit 76ec6a
    void set_memory_label_and_picker(GtkLabel* label, GsmColorButton* picker,
Packit 76ec6a
                                     guint64 used, guint64 total, double percent)
Packit 76ec6a
    {
Packit 76ec6a
        char* used_text;
Packit 76ec6a
        char* total_text;
Packit 76ec6a
        char* text;
Packit 76ec6a
Packit 76ec6a
        used_text = g_format_size_full(used, G_FORMAT_SIZE_IEC_UNITS);
Packit 76ec6a
        total_text = g_format_size_full(total, G_FORMAT_SIZE_IEC_UNITS);
Packit 76ec6a
        if (total == 0) {
Packit 76ec6a
            text = g_strdup(_("not available"));
Packit 76ec6a
        } else {
Packit 76ec6a
            // xgettext: 540MiB (53 %) of 1.0 GiB
Packit 76ec6a
            text = g_strdup_printf(_("%s (%.1f%%) of %s"), used_text, 100.0 * percent, total_text);
Packit 76ec6a
        }
Packit 76ec6a
        gtk_label_set_text(label, text);
Packit 76ec6a
        g_free(used_text);
Packit 76ec6a
        g_free(total_text);
Packit 76ec6a
        g_free(text);
Packit 76ec6a
Packit 76ec6a
        if (picker)
Packit 76ec6a
            gsm_color_button_set_fraction(picker, percent);
Packit 76ec6a
    }
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static void
Packit 76ec6a
get_memory (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    float mempercent, swappercent;
Packit 76ec6a
Packit 76ec6a
    glibtop_mem mem;
Packit 76ec6a
    glibtop_swap swap;
Packit 76ec6a
Packit 76ec6a
    glibtop_get_mem (&mem;;
Packit 76ec6a
    glibtop_get_swap (&swap;;
Packit 76ec6a
Packit 76ec6a
    /* There's no swap on LiveCD : 0.0f is better than NaN :) */
Packit 76ec6a
    swappercent = (swap.total ? (float)swap.used / (float)swap.total : 0.0f);
Packit 76ec6a
    mempercent  = (float)mem.user  / (float)mem.total;
Packit 76ec6a
    set_memory_label_and_picker(GTK_LABEL(graph->labels.memory),
Packit 76ec6a
                                GSM_COLOR_BUTTON(graph->mem_color_picker),
Packit 76ec6a
                                mem.user, mem.total, mempercent);
Packit 76ec6a
Packit 76ec6a
    set_memory_label_and_picker(GTK_LABEL(graph->labels.swap),
Packit 76ec6a
                                GSM_COLOR_BUTTON(graph->swap_color_picker),
Packit 76ec6a
                                swap.used, swap.total, swappercent);
Packit 76ec6a
    
Packit 76ec6a
    gtk_widget_set_sensitive (GTK_WIDGET (graph->swap_color_picker), swap.total > 0);
Packit 76ec6a
    
Packit 76ec6a
    graph->data[0][0] = mempercent;
Packit 76ec6a
    graph->data[0][1] = swap.total>0 ? swappercent : -1.0;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
/* Nice Numbers for Graph Labels after Paul Heckbert
Packit 76ec6a
   nicenum: find a "nice" number approximately equal to x.
Packit 76ec6a
   Round the number if round=1, take ceiling if round=0    */
Packit 76ec6a
Packit 76ec6a
static double
Packit 76ec6a
nicenum (double x, int round)
Packit 76ec6a
{
Packit 76ec6a
    int expv;				/* exponent of x */
Packit 76ec6a
    double f;				/* fractional part of x */
Packit 76ec6a
    double nf;				/* nice, rounded fraction */
Packit 76ec6a
Packit 76ec6a
    expv = floor(log10(x));
Packit 76ec6a
    f = x/pow(10.0, expv);		/* between 1 and 10 */
Packit 76ec6a
    if (round) {
Packit 76ec6a
        if (f < 1.5)
Packit 76ec6a
            nf = 1.0;
Packit 76ec6a
        else if (f < 3.0)
Packit 76ec6a
            nf = 2.0;
Packit 76ec6a
        else if (f < 7.0)
Packit 76ec6a
            nf = 5.0;
Packit 76ec6a
        else
Packit 76ec6a
            nf = 10.0;
Packit 76ec6a
    } else {
Packit 76ec6a
        if (f <= 1.0)
Packit 76ec6a
            nf = 1.0;
Packit 76ec6a
        else if (f <= 2.0)
Packit 76ec6a
            nf = 2.0;
Packit 76ec6a
        else if (f <= 5.0)
Packit 76ec6a
            nf = 5.0;
Packit 76ec6a
        else
Packit 76ec6a
            nf = 10.0;
Packit 76ec6a
    }
Packit 76ec6a
    return nf * pow(10.0, expv);
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static void
Packit 76ec6a
net_scale (LoadGraph *graph, guint64 din, guint64 dout)
Packit 76ec6a
{
Packit 76ec6a
    graph->data[0][0] = 1.0f * din / graph->net.max;
Packit 76ec6a
    graph->data[0][1] = 1.0f * dout / graph->net.max;
Packit 76ec6a
Packit 76ec6a
    guint64 dmax = std::max(din, dout);
Packit 76ec6a
    graph->net.values[graph->net.cur] = dmax;
Packit 76ec6a
    graph->net.cur = (graph->net.cur + 1) % LoadGraph::NUM_POINTS;
Packit 76ec6a
Packit 76ec6a
    guint64 new_max;
Packit 76ec6a
    // both way, new_max is the greatest value
Packit 76ec6a
    if (dmax >= graph->net.max)
Packit 76ec6a
        new_max = dmax;
Packit 76ec6a
    else
Packit 76ec6a
        new_max = *std::max_element(&graph->net.values[0],
Packit 76ec6a
                                    &graph->net.values[LoadGraph::NUM_POINTS]);
Packit 76ec6a
Packit 76ec6a
    //
Packit 76ec6a
    // Round network maximum
Packit 76ec6a
    //
Packit 76ec6a
Packit 76ec6a
    const guint64 bak_max(new_max);
Packit 76ec6a
Packit 76ec6a
    if (GsmApplication::get()->config.network_in_bits) {
Packit 76ec6a
        // nice number is for the ticks
Packit 76ec6a
        unsigned ticks = graph->num_bars();
Packit 76ec6a
Packit 76ec6a
        // gets messy at low values due to division by 8
Packit 76ec6a
        guint64 bit_max = std::max( new_max*8, G_GUINT64_CONSTANT(10000) );
Packit 76ec6a
Packit 76ec6a
        // our tick size leads to max
Packit 76ec6a
        double d = nicenum(bit_max/ticks, 0);
Packit 76ec6a
        bit_max = ticks * d;
Packit 76ec6a
        new_max = bit_max / 8;
Packit 76ec6a
Packit 76ec6a
        procman_debug("bak*8 %" G_GUINT64_FORMAT ", ticks %d, d %f"
Packit 76ec6a
                      ", bit_max %" G_GUINT64_FORMAT ", new_max %" G_GUINT64_FORMAT,
Packit 76ec6a
                      bak_max*8, ticks, d, bit_max, new_max );
Packit 76ec6a
    } else {
Packit 76ec6a
        // round up to get some extra space
Packit 76ec6a
        // yes, it can overflow
Packit 76ec6a
        new_max = 1.1 * new_max;
Packit 76ec6a
        // make sure max is not 0 to avoid / 0
Packit 76ec6a
        // default to 1 KiB
Packit 76ec6a
        new_max = std::max(new_max, G_GUINT64_CONSTANT(1024));
Packit 76ec6a
Packit 76ec6a
        // decompose new_max = coef10 * 2**(base10 * 10)
Packit 76ec6a
        // where coef10 and base10 are integers and coef10 < 2**10
Packit 76ec6a
        //
Packit 76ec6a
        // e.g: ceil(100.5 KiB) = 101 KiB = 101 * 2**(1 * 10)
Packit 76ec6a
        //      where base10 = 1, coef10 = 101, pow2 = 16
Packit 76ec6a
Packit 76ec6a
        guint64 pow2 = std::floor(log2(new_max));
Packit 76ec6a
        guint64 base10 = pow2 / 10.0;
Packit 76ec6a
        guint64 coef10 = std::ceil(new_max / double(G_GUINT64_CONSTANT(1) << (base10 * 10)));
Packit 76ec6a
        g_assert(new_max <= (coef10 * (G_GUINT64_CONSTANT(1) << (base10 * 10))));
Packit 76ec6a
Packit 76ec6a
        // then decompose coef10 = x * 10**factor10
Packit 76ec6a
        // where factor10 is integer and x < 10
Packit 76ec6a
        // so we new_max has only 1 significant digit
Packit 76ec6a
Packit 76ec6a
        guint64 factor10 = std::pow(10.0, std::floor(std::log10(coef10)));
Packit 76ec6a
        coef10 = std::ceil(coef10 / double(factor10)) * factor10;
Packit 76ec6a
Packit 76ec6a
        new_max = coef10 * (G_GUINT64_CONSTANT(1) << guint64(base10 * 10));
Packit 76ec6a
        procman_debug("bak %" G_GUINT64_FORMAT " new_max %" G_GUINT64_FORMAT
Packit 76ec6a
                      "pow2 %" G_GUINT64_FORMAT " coef10 %" G_GUINT64_FORMAT,
Packit 76ec6a
                      bak_max, new_max, pow2, coef10);
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    if (bak_max > new_max) {
Packit 76ec6a
        procman_debug("overflow detected: bak=%" G_GUINT64_FORMAT
Packit 76ec6a
                      " new=%" G_GUINT64_FORMAT,
Packit 76ec6a
                      bak_max, new_max);
Packit 76ec6a
        new_max = bak_max;
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    // if max is the same or has decreased but not so much, don't
Packit 76ec6a
    // do anything to avoid rescaling
Packit 76ec6a
    if ((0.8 * graph->net.max) < new_max && new_max <= graph->net.max)
Packit 76ec6a
        return;
Packit 76ec6a
Packit 76ec6a
    const double scale = 1.0f * graph->net.max / new_max;
Packit 76ec6a
Packit 76ec6a
    for (size_t i = 0; i < LoadGraph::NUM_POINTS; i++) {
Packit 76ec6a
        if (graph->data[i][0] >= 0.0f) {
Packit 76ec6a
            graph->data[i][0] *= scale;
Packit 76ec6a
            graph->data[i][1] *= scale;
Packit 76ec6a
        }
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    procman_debug("rescale dmax = %" G_GUINT64_FORMAT
Packit 76ec6a
                  " max = %" G_GUINT64_FORMAT
Packit 76ec6a
                  " new_max = %" G_GUINT64_FORMAT,
Packit 76ec6a
                  dmax, graph->net.max, new_max);
Packit 76ec6a
Packit 76ec6a
    graph->net.max = new_max;
Packit 76ec6a
Packit 76ec6a
    // force the graph background to be redrawn now that scale has changed
Packit 76ec6a
    graph->clear_background();
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
static void
Packit 76ec6a
get_net (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    glibtop_netlist netlist;
Packit 76ec6a
    char **ifnames;
Packit 76ec6a
    guint32 i;
Packit 76ec6a
    guint64 in = 0, out = 0;
Packit 76ec6a
    GTimeVal time;
Packit 76ec6a
    guint64 din, dout;
Packit 76ec6a
    gboolean first = true;
Packit 76ec6a
    ifnames = glibtop_get_netlist(&netlist);
Packit 76ec6a
Packit 76ec6a
    for (i = 0; i < netlist.number; ++i)
Packit 76ec6a
    {
Packit 76ec6a
        glibtop_netload netload;
Packit 76ec6a
        glibtop_get_netload (&netload, ifnames[i]);
Packit 76ec6a
Packit 76ec6a
        if (netload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK))
Packit 76ec6a
            continue;
Packit 76ec6a
Packit 76ec6a
        /* Skip interfaces without any IPv4/IPv6 address (or
Packit 76ec6a
           those with only a LINK ipv6 addr) However we need to
Packit 76ec6a
           be able to exclude these while still keeping the
Packit 76ec6a
           value so when they get online (with NetworkManager
Packit 76ec6a
           for example) we don't get a suddent peak.  Once we're
Packit 76ec6a
           able to get this, ignoring down interfaces will be
Packit 76ec6a
           possible too.  */
Packit 76ec6a
        if (not (netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS6)
Packit 76ec6a
                 and netload.scope6 != GLIBTOP_IF_IN6_SCOPE_LINK)
Packit 76ec6a
            and not (netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS)))
Packit 76ec6a
            continue;
Packit 76ec6a
Packit 76ec6a
        /* Don't skip interfaces that are down (GLIBTOP_IF_FLAGS_UP)
Packit 76ec6a
           to avoid spikes when they are brought up */
Packit 76ec6a
Packit 76ec6a
        in  += netload.bytes_in;
Packit 76ec6a
        out += netload.bytes_out;
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    g_strfreev(ifnames);
Packit 76ec6a
Packit 76ec6a
    g_get_current_time (&time);
Packit 76ec6a
Packit 76ec6a
    if (in >= graph->net.last_in && out >= graph->net.last_out && graph->net.time.tv_sec != 0) {
Packit 76ec6a
        float dtime;
Packit 76ec6a
        dtime = time.tv_sec - graph->net.time.tv_sec +
Packit 76ec6a
                (double) (time.tv_usec - graph->net.time.tv_usec) / G_USEC_PER_SEC;
Packit 76ec6a
        din   = static_cast<guint64>((in  - graph->net.last_in)  / dtime);
Packit 76ec6a
        dout  = static_cast<guint64>((out - graph->net.last_out) / dtime);
Packit 76ec6a
    } else {
Packit 76ec6a
        /* Don't calc anything if new data is less than old (interface
Packit 76ec6a
           removed, counters reset, ...) or if it is the first time */
Packit 76ec6a
        din  = 0;
Packit 76ec6a
        dout = 0;
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    first = first && (graph->net.time.tv_sec==0);
Packit 76ec6a
    graph->net.last_in  = in;
Packit 76ec6a
    graph->net.last_out = out;
Packit 76ec6a
    graph->net.time     = time;
Packit 76ec6a
Packit 76ec6a
    if (!first)
Packit 76ec6a
        net_scale(graph, din, dout);
Packit 76ec6a
Packit 76ec6a
    gtk_label_set_text (GTK_LABEL (graph->labels.net_in), procman::format_network_rate(din).c_str());
Packit 76ec6a
    gtk_label_set_text (GTK_LABEL (graph->labels.net_in_total), procman::format_network(in).c_str());
Packit 76ec6a
Packit 76ec6a
    gtk_label_set_text (GTK_LABEL (graph->labels.net_out), procman::format_network_rate(dout).c_str());
Packit 76ec6a
    gtk_label_set_text (GTK_LABEL (graph->labels.net_out_total), procman::format_network(out).c_str());
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
/* Updates the load graph when the timeout expires */
Packit 76ec6a
static gboolean
Packit 76ec6a
load_graph_update (gpointer user_data)
Packit 76ec6a
{
Packit 76ec6a
    LoadGraph * const graph = static_cast<LoadGraph*>(user_data);
Packit 76ec6a
Packit 76ec6a
    if (graph->render_counter == graph->frames_per_unit - 1) {
Packit 76ec6a
        std::rotate(&graph->data[0],
Packit 76ec6a
                    &graph->data[LoadGraph::NUM_POINTS - 1],
Packit 76ec6a
                    &graph->data[LoadGraph::NUM_POINTS]);
Packit 76ec6a
Packit 76ec6a
        switch (graph->type) {
Packit 76ec6a
            case LOAD_GRAPH_CPU:
Packit 76ec6a
                get_load(graph);
Packit 76ec6a
                break;
Packit 76ec6a
            case LOAD_GRAPH_MEM:
Packit 76ec6a
                get_memory(graph);
Packit 76ec6a
                break;
Packit 76ec6a
            case LOAD_GRAPH_NET:
Packit 76ec6a
                get_net(graph);
Packit 76ec6a
                break;
Packit 76ec6a
            default:
Packit 76ec6a
                g_assert_not_reached();
Packit 76ec6a
        }
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    if (graph->draw)
Packit 76ec6a
        load_graph_queue_draw (graph);
Packit 76ec6a
Packit 76ec6a
    graph->render_counter++;
Packit 76ec6a
Packit 76ec6a
    if (graph->render_counter >= graph->frames_per_unit)
Packit 76ec6a
        graph->render_counter = 0;
Packit 76ec6a
Packit 76ec6a
    return TRUE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
LoadGraph::~LoadGraph()
Packit 76ec6a
{
Packit 76ec6a
    load_graph_stop(this);
Packit 76ec6a
Packit 76ec6a
    if (timer_index)
Packit 76ec6a
        g_source_remove(timer_index);
Packit 76ec6a
Packit 76ec6a
    clear_background();
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
static gboolean
Packit 76ec6a
load_graph_destroy (GtkWidget *widget, gpointer data_ptr)
Packit 76ec6a
{
Packit 76ec6a
    LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
Packit 76ec6a
Packit 76ec6a
    delete graph;
Packit 76ec6a
Packit 76ec6a
    return FALSE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
LoadGraph::LoadGraph(guint type)
Packit 76ec6a
    : fontsize(8.0),
Packit 76ec6a
      rmargin(7 * fontsize),
Packit 76ec6a
      indent(24.0),
Packit 76ec6a
      n(0),
Packit 76ec6a
      type(type),
Packit 76ec6a
      speed(0),
Packit 76ec6a
      draw_width(0),
Packit 76ec6a
      draw_height(0),
Packit 76ec6a
      render_counter(0),
Packit 76ec6a
      frames_per_unit(10), // this will be changed but needs initialising
Packit 76ec6a
      graph_dely(0),
Packit 76ec6a
      real_draw_height(0),
Packit 76ec6a
      graph_delx(0.0),
Packit 76ec6a
      graph_buffer_offset(0),
Packit 76ec6a
      colors(),
Packit 76ec6a
      data_block(),
Packit 76ec6a
      main_widget(NULL),
Packit 76ec6a
      disp(NULL),
Packit 76ec6a
      background(NULL),
Packit 76ec6a
      timer_index(0),
Packit 76ec6a
      draw(FALSE),
Packit 76ec6a
      labels(),
Packit 76ec6a
      mem_color_picker(NULL),
Packit 76ec6a
      swap_color_picker(NULL),
Packit 76ec6a
      cpu(),
Packit 76ec6a
      net()
Packit 76ec6a
{
Packit 76ec6a
    LoadGraph * const graph = this;
Packit 76ec6a
Packit 76ec6a
    // FIXME:
Packit 76ec6a
    // on configure, graph->frames_per_unit = graph->draw_width/(LoadGraph::NUM_POINTS);
Packit 76ec6a
    // knock FRAMES down to 5 until cairo gets faster
Packit 76ec6a
Packit 76ec6a
    switch (type) {
Packit 76ec6a
        case LOAD_GRAPH_CPU:
Packit 76ec6a
            memset(&cpu, 0, sizeof cpu);
Packit 76ec6a
            n = GsmApplication::get()->config.num_cpus;
Packit 76ec6a
Packit 76ec6a
            for(guint i = 0; i < G_N_ELEMENTS(labels.cpu); ++i)
Packit 76ec6a
                labels.cpu[i] = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
Packit 76ec6a
            break;
Packit 76ec6a
Packit 76ec6a
        case LOAD_GRAPH_MEM:
Packit 76ec6a
            n = 2;
Packit 76ec6a
            labels.memory = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
            gtk_widget_set_valign (GTK_WIDGET (labels.memory), GTK_ALIGN_CENTER);
Packit 76ec6a
            gtk_widget_set_halign (GTK_WIDGET (labels.memory), GTK_ALIGN_START);
Packit 76ec6a
            gtk_widget_show (GTK_WIDGET (labels.memory));
Packit 76ec6a
            labels.swap = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
            gtk_widget_set_valign (GTK_WIDGET (labels.swap), GTK_ALIGN_CENTER);
Packit 76ec6a
            gtk_widget_set_halign (GTK_WIDGET (labels.swap), GTK_ALIGN_START);
Packit 76ec6a
            gtk_widget_show (GTK_WIDGET (labels.swap));
Packit 76ec6a
            break;
Packit 76ec6a
Packit 76ec6a
        case LOAD_GRAPH_NET:
Packit 76ec6a
            memset(&net, 0, sizeof net);
Packit 76ec6a
            n = 2;
Packit 76ec6a
            net.max = 1;
Packit 76ec6a
            labels.net_in = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
            gtk_label_set_width_chars(labels.net_in, 10);
Packit 76ec6a
            gtk_widget_set_valign (GTK_WIDGET (labels.net_in), GTK_ALIGN_CENTER);
Packit 76ec6a
            gtk_widget_set_halign (GTK_WIDGET (labels.net_in), GTK_ALIGN_END);
Packit 76ec6a
            gtk_widget_show (GTK_WIDGET (labels.net_in));
Packit 76ec6a
Packit 76ec6a
            labels.net_in_total = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
            gtk_widget_set_valign (GTK_WIDGET (labels.net_in_total), GTK_ALIGN_CENTER);
Packit 76ec6a
            gtk_widget_set_halign (GTK_WIDGET (labels.net_in_total), GTK_ALIGN_END);
Packit 76ec6a
            gtk_label_set_width_chars(labels.net_in_total, 10);
Packit 76ec6a
            gtk_widget_show (GTK_WIDGET (labels.net_in_total));
Packit 76ec6a
Packit 76ec6a
            labels.net_out = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
            gtk_widget_set_valign (GTK_WIDGET (labels.net_out), GTK_ALIGN_CENTER);
Packit 76ec6a
            gtk_widget_set_halign (GTK_WIDGET (labels.net_out), GTK_ALIGN_END);
Packit 76ec6a
            gtk_label_set_width_chars(labels.net_out, 10);
Packit 76ec6a
            gtk_widget_show (GTK_WIDGET (labels.net_out));
Packit 76ec6a
Packit 76ec6a
            labels.net_out_total = GTK_LABEL (gtk_label_new(NULL));
Packit 76ec6a
            gtk_widget_set_valign (GTK_WIDGET (labels.net_out_total), GTK_ALIGN_CENTER);
Packit 76ec6a
            gtk_widget_set_halign (GTK_WIDGET (labels.net_out), GTK_ALIGN_END);
Packit 76ec6a
            gtk_label_set_width_chars(labels.net_out_total, 10);
Packit 76ec6a
            gtk_widget_show (GTK_WIDGET (labels.net_out_total));
Packit 76ec6a
Packit 76ec6a
            break;
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    speed  = GsmApplication::get()->config.graph_update_interval;
Packit 76ec6a
Packit 76ec6a
    colors.resize(n);
Packit 76ec6a
Packit 76ec6a
    switch (type) {
Packit 76ec6a
        case LOAD_GRAPH_CPU:
Packit 76ec6a
            memcpy(&colors[0], GsmApplication::get()->config.cpu_color,
Packit 76ec6a
                   n * sizeof colors[0]);
Packit 76ec6a
            break;
Packit 76ec6a
        case LOAD_GRAPH_MEM:
Packit 76ec6a
            colors[0] = GsmApplication::get()->config.mem_color;
Packit 76ec6a
            colors[1] = GsmApplication::get()->config.swap_color;
Packit 76ec6a
            mem_color_picker = gsm_color_button_new (&colors[0],
Packit 76ec6a
                                                        GSMCP_TYPE_PIE);
Packit 76ec6a
            swap_color_picker = gsm_color_button_new (&colors[1],
Packit 76ec6a
                                                         GSMCP_TYPE_PIE);
Packit 76ec6a
            break;
Packit 76ec6a
        case LOAD_GRAPH_NET:
Packit 76ec6a
            colors[0] = GsmApplication::get()->config.net_in_color;
Packit 76ec6a
            colors[1] = GsmApplication::get()->config.net_out_color;
Packit 76ec6a
            break;
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    timer_index = 0;
Packit 76ec6a
    render_counter = (frames_per_unit - 1);
Packit 76ec6a
    draw = FALSE;
Packit 76ec6a
Packit 76ec6a
    main_widget = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
Packit 76ec6a
    gtk_widget_set_size_request(GTK_WIDGET (main_widget), -1, LoadGraph::GRAPH_MIN_HEIGHT);
Packit 76ec6a
    gtk_widget_show (GTK_WIDGET (main_widget));
Packit 76ec6a
Packit 76ec6a
    disp = GTK_DRAWING_AREA (gtk_drawing_area_new ());
Packit 76ec6a
    gtk_widget_show (GTK_WIDGET (disp));
Packit 76ec6a
    g_signal_connect (G_OBJECT (disp), "draw",
Packit 76ec6a
                      G_CALLBACK (load_graph_draw), graph);
Packit 76ec6a
    g_signal_connect (G_OBJECT(disp), "configure_event",
Packit 76ec6a
                      G_CALLBACK (load_graph_configure), graph);
Packit 76ec6a
    g_signal_connect (G_OBJECT(disp), "destroy",
Packit 76ec6a
                      G_CALLBACK (load_graph_destroy), graph);
Packit 76ec6a
    g_signal_connect (G_OBJECT(disp), "state-flags-changed",
Packit 76ec6a
                      G_CALLBACK (load_graph_state_changed), graph);
Packit 76ec6a
    g_signal_connect (G_OBJECT(disp), "style-updated",
Packit 76ec6a
                      G_CALLBACK (load_graph_style_updated), graph);
Packit 76ec6a
Packit 76ec6a
    gtk_widget_set_events (GTK_WIDGET (disp), GDK_EXPOSURE_MASK);
Packit 76ec6a
Packit 76ec6a
    gtk_box_pack_start (main_widget, GTK_WIDGET (disp), TRUE, TRUE, 0);
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
    /* Allocate data in a contiguous block */
Packit 76ec6a
    data_block = std::vector<double>(n * LoadGraph::NUM_POINTS, -1.0);
Packit 76ec6a
Packit 76ec6a
    for (guint i = 0; i < LoadGraph::NUM_POINTS; ++i)
Packit 76ec6a
        data[i] = &data_block[0] + i * n;
Packit 76ec6a
Packit 76ec6a
    gtk_widget_show_all (GTK_WIDGET (main_widget));
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
void
Packit 76ec6a
load_graph_start (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
     if (!graph->timer_index) {
Packit 76ec6a
Packit 76ec6a
        load_graph_update(graph);
Packit 76ec6a
Packit 76ec6a
        graph->timer_index = g_timeout_add (graph->speed / graph->frames_per_unit,
Packit 76ec6a
                                            load_graph_update,
Packit 76ec6a
                                            graph);
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    graph->draw = TRUE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
void
Packit 76ec6a
load_graph_stop (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    /* don't draw anymore, but continue to poll */
Packit 76ec6a
    graph->draw = FALSE;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
void
Packit 76ec6a
load_graph_change_speed (LoadGraph *graph,
Packit 76ec6a
                         guint new_speed)
Packit 76ec6a
{
Packit 76ec6a
    if (graph->speed == new_speed)
Packit 76ec6a
        return;
Packit 76ec6a
Packit 76ec6a
    graph->speed = new_speed;
Packit 76ec6a
Packit 76ec6a
    if (graph->timer_index) {
Packit 76ec6a
        g_source_remove (graph->timer_index);
Packit 76ec6a
        graph->timer_index = g_timeout_add (graph->speed / graph->frames_per_unit,
Packit 76ec6a
                                            load_graph_update,
Packit 76ec6a
                                            graph);
Packit 76ec6a
    }
Packit 76ec6a
Packit 76ec6a
    graph->clear_background();
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
Packit 76ec6a
LoadGraphLabels*
Packit 76ec6a
load_graph_get_labels (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    return &graph->labels;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
GtkBox*
Packit 76ec6a
load_graph_get_widget (LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    return graph->main_widget;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
GsmColorButton*
Packit 76ec6a
load_graph_get_mem_color_picker(LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    return graph->mem_color_picker;
Packit 76ec6a
}
Packit 76ec6a
Packit 76ec6a
GsmColorButton*
Packit 76ec6a
load_graph_get_swap_color_picker(LoadGraph *graph)
Packit 76ec6a
{
Packit 76ec6a
    return graph->swap_color_picker;
Packit 76ec6a
}