📄 mon-gnome.c
字号:
/* -*- c-file-style: "k&r"; c-basic-offset: 4; indent-tabs-mode: nil; -*- * * distcc -- A simple distributed compiler system * * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA *//* * @file * * Gnome 2.x monitor for distcc. * * For each slot we have a record in a tree model, including an array * indicating the past states. This is stored in the "history" column * of the TreeMode for that slot. * * The renderer knows how to walk over the queue and draw state * rectangles for the values it finds. The queue is implemented as a * circular array, whose values are initialized to idle. * * Starved jobs are currently not shown in the chart view. * * Colors should perhaps be customizable with reasonable defaults. *//* FIXME: When the dialogs are dismissed, they seem to get destroyed. We need to make sure that they just get hidden and can be summoned again. *//* last one using chart drawingarea is 1.43.2.37 */#include "config.h"#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <pwd.h>#include <unistd.h>#ifdef HAVE_SYS_LOADAVG_H# include <sys/loadavg.h>#endif#ifdef WITH_GNOME# include <gnome.h>#endif#include <gtk/gtk.h>#include "types.h"#include "distcc.h"#include "rpc.h"#include "trace.h"#include "exitcode.h"#include "mon.h"#include "renderer.h"const char *rs_program_name = "distccmon-gnome";static GtkWidget *chart_treeview;static GtkListStore *chart_model;/* Note: these must match the types given in order in the call to gtk_list_store_new() */enum { COLUMN_HOST, COLUMN_SLOT, COLUMN_FILE, COLUMN_STATE, COLUMN_HISTORY,};/** * Graphics contexts to be used to draw each particular state into the * model. **/GdkGC *dcc_phase_gc[DCC_PHASE_DONE];#if 0/* shades of red */const GdkColor task_color[] = { { 0, 0x2222, 0, 0 }, /* DCC_PHASE_STARTUP, */ { 0, 0x4444, 0, 0 }, /* DCC_PHASE_BLOCKED, */ { 0, 0x6666, 0, 0 }, /* DCC_PHASE_CONNECT, */ { 0, 0x8888, 0, 0 }, /* DCC_PHASE_CPP, */ { 0, 0xaaaa, 0, 0 }, /* DCC_PHASE_SEND, */ { 0, 0xcccc, 0, 0 }, /* DCC_PHASE_COMPILE, */ { 0, 0xeeee, 0, 0 }, /* DCC_PHASE_RECEIVE, */ { 0, 0xffff, 0xffff, 0 }, /* DCC_PHASE_DONE */};#endif/* * Colors used for drawing different state stripes. First GdkColor * field is the assigned color index and zero here. * * These color names are from the GNOME standard palette. */const GdkColor task_color[] = { { 0, 0x9999, 0, 0 }, /* DCC_PHASE_STARTUP, accent red dark */ { 0, 0x9999, 0, 0 }, /* DCC_PHASE_BLOCKED, accent red dark */ { 0, 0xc1c1, 0x6666, 0x5a5a }, /* DCC_PHASE_CONNECT, red medium */ { 0, 0x8888, 0x7f7f, 0xa3a3 }, /* DCC_PHASE_CPP, purple medium*/ { 0, 0xe0e0, 0xc3c3, 0x9e9e }, /* DCC_PHASE_SEND, face skin medium*/ { 0, 0x8383, 0xa6a6, 0x7f7f }, /* DCC_PHASE_COMPILE, green medium */ { 0, 0x7575, 0x9090, 0xaeae }, /* DCC_PHASE_RECEIVE, blue medium*/ { 0, 0, 0, 0 }, /* DCC_PHASE_DONE */};static voiddcc_setup_tree_model (void){ /* Create a table for process status */ chart_model = gtk_list_store_new (5, G_TYPE_STRING, /* host */ G_TYPE_INT, /* slot */ G_TYPE_STRING, /* file */ G_TYPE_STRING, /* state */ G_TYPE_POINTER /* history */ );}static voiddcc_row_history_push (GtkListStore *model, GtkTreeIter *tree_iter, enum dcc_phase new_state){ struct dcc_history *history; gtk_tree_model_get(GTK_TREE_MODEL (model), tree_iter, COLUMN_HISTORY, &history, -1); dcc_history_push(history, new_state); /* Perhaps we should call gtk_tree_model_row_changed(), but at the moment every call to this is associated with some other change to the model so I don't think there's any need. */}static voiddcc_set_row_from_task (GtkListStore *model, GtkTreeIter *tree_iter, struct dcc_task_state *task){ dcc_row_history_push (model, tree_iter, task->curr_phase); gtk_list_store_set (model, tree_iter, COLUMN_HOST, task->host, COLUMN_SLOT, task->slot, COLUMN_FILE, task->file, COLUMN_STATE, dcc_get_phase_name(task->curr_phase), -1);}static voiddcc_insert_row_from_task (GtkListStore *model, GtkTreeIter *tree_iter, GtkTreeIter *insert_before, struct dcc_task_state *task_iter){ struct dcc_history *history; history = dcc_history_new(); dcc_history_push(history, task_iter->curr_phase); gtk_list_store_insert_before(chart_model, tree_iter, insert_before); gtk_list_store_set(model, tree_iter, COLUMN_HOST, task_iter->host, COLUMN_SLOT, task_iter->slot, COLUMN_FILE, task_iter->file, COLUMN_STATE, dcc_get_phase_name(task_iter->curr_phase), COLUMN_HISTORY, history, -1);}static voiddcc_set_row_idle(GtkListStore *model, GtkTreeIter *tree_iter){ struct dcc_history *history; gtk_tree_model_get(GTK_TREE_MODEL (model), tree_iter, COLUMN_HISTORY, &history, -1); /* only write to the treemodel if it was previously non-idle */ if (history->past_phases[history->now] != DCC_PHASE_DONE) { gtk_list_store_set (model, tree_iter, COLUMN_FILE, NULL, COLUMN_STATE, NULL, -1); } else { /* it still changed... */ GtkTreePath *path; path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), tree_iter); gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, tree_iter); gtk_tree_path_free(path); } dcc_history_push(history, DCC_PHASE_DONE);}/** * * We update the list model in place by looking for slots which have a * different state to last time we polled. * * mon.c always returns state records to us in a consistent order, * sorted by hostname and then by slot. The list model is always held * in the same order. Over time some slots may become empty, or some * new slots may be used. * * Walking through the task list and the tree store in order makes it * fairly easy to see where tasks have been inserted, removed, or * changed. * * When there is no task for a row, we don't remove the row from the * list model. This is for two reasons: one is that it stops rows * bouncing around too much when they're not fully loaded. In the * future when we draw a state history, this will allow rows to * persist showing what they did in the past, even if they're doing * nothing now. * * Every time through, we update each table row exactly once, whether * that is adding new state, settting it back to idle, or inserting * it. In particular, on each pass we add one value to the start of * every state history. **/static voiddcc_update_store_from_tasks (struct dcc_task_state *task_list){ struct dcc_task_state *task_iter; GtkTreeIter tree_iter[1]; gboolean tree_valid; int cmp; GtkTreeModel *tree_model = GTK_TREE_MODEL (chart_model); tree_valid = gtk_tree_model_get_iter_first (tree_model, tree_iter); for (task_iter = task_list; task_iter != NULL && tree_valid; ) { gchar *row_host; int row_slot; if (task_iter->curr_phase == DCC_PHASE_DONE || task_iter->host[0] == '\0' || task_iter->file[0] == '\0') { /* skip this */ task_iter = task_iter->next; continue; } gtk_tree_model_get (tree_model, tree_iter, COLUMN_HOST, &row_host, COLUMN_SLOT, &row_slot, -1); cmp = strcmp (task_iter->host, row_host); if (cmp == 0) cmp = task_iter->slot - row_slot; g_free(row_host);/* g_message ("host %s, slot %d, file %s -> cmp=%d", *//* task_iter->host, task_iter->slot, task_iter->file, cmp); */ /* What is the relative order of the task and the row, based on host and slot? */ if (cmp == 0) { /* If the task and row match, then update the row from the task if necessary */ dcc_set_row_from_task (chart_model, tree_iter, task_iter); /* Proceed to next task and row */ task_iter = task_iter->next; } else if (cmp < 0) { /* If this task comes before the row, then the task must be on a slot that is not yet on the table store. Insert a row. *//* g_message ("insert row for host %s, slot %d", *//* task_iter->host, task_iter->slot); */ dcc_insert_row_from_task (chart_model, tree_iter, tree_iter, task_iter); /* Proceed to next task and the row after the one we just inserted. */ task_iter = task_iter->next; } else /* cmp > 0 */ { /* If this row comes before the current task, then the row must be for a slot that's no longer in use. Clear the row */ dcc_set_row_idle (chart_model, tree_iter); /* Compare next row against the same task */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -