Advertisement
Guest User

Gnome-system-monitor - rounded graphs

a guest
Dec 20th, 2012
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.68 KB | None | 0 0
  1. #include <config.h>
  2.  
  3. #include <gdkmm/pixbuf.h>
  4.  
  5. #include <stdio.h>
  6. #include <sys/stat.h>
  7. #include <unistd.h>
  8. #include <signal.h>
  9. #include <dirent.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include <gdk/gdkx.h>
  13.  
  14. #include <glib/gi18n.h>
  15.  
  16. #include <glibtop.h>
  17. #include <glibtop/cpu.h>
  18. #include <glibtop/mem.h>
  19. #include <glibtop/swap.h>
  20. #include <glibtop/netload.h>
  21. #include <glibtop/netlist.h>
  22. #include <math.h>
  23.  
  24. #include <algorithm>
  25.  
  26. #include "procman.h"
  27. #include "load-graph.h"
  28. #include "util.h"
  29. #include "gsm_color_button.h"
  30.  
  31.  
  32. void LoadGraph::clear_background()
  33. {
  34. if (background) {
  35. cairo_surface_destroy (background);
  36. background = NULL;
  37. }
  38. }
  39.  
  40.  
  41. unsigned LoadGraph::num_bars() const
  42. {
  43. unsigned n;
  44.  
  45. // keep 100 % num_bars == 0
  46. switch (static_cast<int>(draw_height / (fontsize + 14)))
  47. {
  48. case 0:
  49. case 1:
  50. n = 1;
  51. break;
  52. case 2:
  53. case 3:
  54. n = 2;
  55. break;
  56. case 4:
  57. n = 4;
  58. break;
  59. default:
  60. n = 5;
  61. }
  62.  
  63. return n;
  64. }
  65.  
  66.  
  67.  
  68. #define FRAME_WIDTH 4
  69. void draw_background(LoadGraph *graph) {
  70. GtkAllocation allocation;
  71. double dash[2] = { 2.0, 2.0 };
  72. cairo_t *cr;
  73. guint i;
  74. unsigned num_bars;
  75. char *caption;
  76. PangoLayout* layout;
  77. PangoFontDescription* font_desc;
  78. PangoRectangle extents;
  79.  
  80. num_bars = graph->num_bars();
  81. graph->graph_dely = (graph->draw_height - 15) / num_bars; /* round to int to avoid AA blur */
  82. graph->real_draw_height = graph->graph_dely * num_bars;
  83. graph->graph_delx = (graph->draw_width - 2.0 - graph->rmargin - graph->indent) / (LoadGraph::NUM_POINTS - 3);
  84. graph->graph_buffer_offset = (int) (1.5 * graph->graph_delx) + FRAME_WIDTH ;
  85.  
  86. gtk_widget_get_allocation (graph->disp, &allocation);
  87. graph->background = gdk_window_create_similar_surface (gtk_widget_get_window (graph->disp),
  88. CAIRO_CONTENT_COLOR,
  89. allocation.width,
  90. allocation.height);
  91. cr = cairo_create (graph->background);
  92.  
  93. // set the background colour
  94. GtkStyle *style = gtk_widget_get_style (ProcData::get_instance()->notebook);
  95. cairo_set_source_rgba (cr, 0.97, 0.97, 0.97, 0.97);
  96. cairo_fill(cr);
  97. cairo_paint (cr);
  98.  
  99. layout = pango_cairo_create_layout (cr);
  100. font_desc = pango_font_description_copy (style->font_desc);
  101. pango_font_description_set_size (font_desc, 0.8 * graph->fontsize * PANGO_SCALE);
  102. pango_layout_set_font_description (layout, font_desc);
  103. pango_font_description_free (font_desc);
  104.  
  105. /* draw frame */
  106. /* a custom shape that could be wrapped in a function */
  107. double x = 0.2, /* parameters like cairo_rectangle */
  108. y = 0.2,
  109. width = allocation.width,
  110. height = allocation.height,
  111. aspect = 1.0, /* aspect ratio */
  112. corner_radius = height / 14.0; /* and corner curvature radius */
  113.  
  114. double radius = corner_radius / aspect;
  115. double degrees = M_PI / 180.0;
  116.  
  117. cairo_new_sub_path (cr);
  118. cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
  119. cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
  120. cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
  121. cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
  122. cairo_close_path (cr);
  123.  
  124. cairo_set_source_rgb (cr, 0.03, 0.03, 0.03);
  125. cairo_fill_preserve (cr);
  126. cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
  127. cairo_set_line_width (cr, 1.0);
  128. cairo_stroke (cr);
  129.  
  130. cr = cairo_create (graph->background);
  131.  
  132. /* Draw background rectangle */
  133.  
  134. cairo_set_dash (cr, dash, 2, 0);
  135.  
  136. for (i = 0; i <= num_bars; ++i) {
  137. double y;
  138.  
  139. if (i == 0)
  140. y = 0.5 + graph->fontsize / 2.0;
  141. else if (i == num_bars)
  142. y = i * graph->graph_dely + 0.5;
  143. else
  144. y = i * graph->graph_dely + graph->fontsize / 2.0;
  145.  
  146. gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
  147. if (graph->type == LOAD_GRAPH_NET) {
  148. // operation orders matters so it's 0 if i == num_bars
  149. guint64 rate = graph->net.max - (i * graph->net.max / num_bars);
  150. const std::string caption(procman::format_network_rate(rate, graph->net.max));
  151. pango_layout_set_text (layout, caption.c_str(), -1);
  152. pango_layout_get_extents (layout, NULL, &extents);
  153. cairo_move_to (cr, graph->indent - 1.0 * extents.width / PANGO_SCALE + 20,
  154. y - 1.0 * extents.height / PANGO_SCALE / 2);
  155. pango_cairo_show_layout (cr, layout);
  156. } else {
  157. // operation orders matters so it's 0 if i == num_bars
  158. caption = g_strdup_printf("%d%%", 100 - i * (100 / num_bars));
  159. pango_layout_set_text (layout, caption, -1);
  160. pango_layout_get_extents (layout, NULL, &extents);
  161. cairo_move_to (cr, graph->indent - 1.0 * extents.width / PANGO_SCALE + 20,
  162. y - 1.0 * extents.height / PANGO_SCALE / 2);
  163. pango_cairo_show_layout (cr, layout);
  164. g_free (caption);
  165. }
  166.  
  167. cairo_set_source_rgba (cr, 0.3, 0.3, 0.3, 0.35);
  168. cairo_move_to (cr, graph->rmargin + graph->indent - 3, i * graph->graph_dely + 0.5);
  169. cairo_line_to (cr, graph->draw_width - 0.5, i * graph->graph_dely + 0.5);
  170. }
  171. cairo_stroke (cr);
  172.  
  173. cairo_set_dash (cr, dash, 2, 0.5);
  174.  
  175. const unsigned total_seconds = graph->speed * (LoadGraph::NUM_POINTS - 2) / 1000;
  176.  
  177. for (unsigned int i = 0; i < 7; i++) {
  178. double x = (i) * (graph->draw_width - graph->rmargin - graph->indent) / 6;
  179. cairo_set_source_rgba (cr, 0, 0, 0, 0.75);
  180. cairo_move_to (cr, (ceil(x) + 0.5) + graph->rmargin + graph->indent, 0.5);
  181. cairo_line_to (cr, (ceil(x) + 0.5) + graph->rmargin + graph->indent, graph->real_draw_height + 4.5);
  182. cairo_stroke(cr);
  183. unsigned seconds = total_seconds - i * total_seconds / 6;
  184. const char* format;
  185. if (i == 0)
  186. format = dngettext(GETTEXT_PACKAGE, "%u second", "%u seconds", seconds);
  187. else
  188. format = "%u";
  189. caption = g_strdup_printf(format, seconds);
  190. pango_layout_set_text (layout, caption, -1);
  191. pango_layout_get_extents (layout, NULL, &extents);
  192. cairo_move_to (cr,
  193. (ceil(x) + 0.5 + graph->rmargin + graph->indent) - (1.0 * extents.width / PANGO_SCALE / 2),
  194. graph->draw_height - 1.0 * extents.height / PANGO_SCALE);
  195. gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
  196. pango_cairo_show_layout (cr, layout);
  197. g_free (caption);
  198. }
  199. g_object_unref(layout);
  200. cairo_stroke (cr);
  201. cairo_destroy (cr);
  202. }
  203.  
  204. /* Redraws the backing buffer for the load graph and updates the window */
  205. void
  206. load_graph_queue_draw (LoadGraph *graph)
  207. {
  208. /* repaint */
  209. gtk_widget_queue_draw (graph->disp);
  210. }
  211.  
  212. static int load_graph_update (gpointer user_data); // predeclare load_graph_update so we can compile ;)
  213.  
  214. static gboolean
  215. load_graph_configure (GtkWidget *widget,
  216. GdkEventConfigure *event,
  217. gpointer data_ptr)
  218. {
  219. GtkAllocation allocation;
  220. LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
  221.  
  222. gtk_widget_get_allocation (widget, &allocation);
  223. graph->draw_width = allocation.width - 2 * FRAME_WIDTH;
  224. graph->draw_height = allocation.height - 2 * FRAME_WIDTH;
  225.  
  226. graph->clear_background();
  227.  
  228. load_graph_queue_draw (graph);
  229.  
  230. return TRUE;
  231. }
  232.  
  233. static gboolean
  234. load_graph_draw (GtkWidget *widget,
  235. cairo_t * context,
  236. gpointer data_ptr)
  237. {
  238. LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
  239. GdkWindow *window;
  240.  
  241. guint i, j;
  242. gdouble sample_width, x_offset;
  243.  
  244. window = gtk_widget_get_window (graph->disp);
  245.  
  246. if (graph->background == NULL) {
  247. draw_background(graph);
  248. cairo_pattern_t * pattern = cairo_pattern_create_for_surface (graph->background);
  249. gdk_window_set_background_pattern (window, pattern);
  250. cairo_pattern_destroy (pattern);
  251. }
  252.  
  253. /* Number of pixels wide for one graph point */
  254. sample_width = (float)(graph->draw_width - graph->rmargin - graph->indent) / (float)LoadGraph::NUM_POINTS;
  255. /* General offset */
  256. x_offset = graph->draw_width - graph->rmargin + (sample_width*2);
  257.  
  258. /* Subframe offset */
  259. x_offset += graph->rmargin - ((sample_width / graph->frames_per_unit) * graph->render_counter);
  260.  
  261. /* draw the graph */
  262. cairo_t* cr;
  263.  
  264. cr = gdk_cairo_create (window);
  265.  
  266. cairo_set_line_width (cr, 2);
  267. cairo_set_source_rgba (cr, 0.3, 0.3, 0.3, 0.35);
  268. cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
  269. cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
  270. cairo_rectangle (cr, graph->rmargin + graph->indent + FRAME_WIDTH + 1, FRAME_WIDTH - 1,
  271. graph->draw_width - graph->rmargin - graph->indent - 1,
  272. graph->real_draw_height + FRAME_WIDTH - 1);
  273. cairo_clip(cr);
  274.  
  275. for (j = 0; j < graph->n; ++j) {
  276. cairo_move_to (cr, x_offset, (1.0f - graph->data[0][j]) * graph->real_draw_height);
  277. gdk_cairo_set_source_color (cr, &(graph->colors [j]));
  278.  
  279. for (i = 1; i < LoadGraph::NUM_POINTS; ++i) {
  280. if (graph->data[i][j] == -1.0f)
  281. continue;
  282. cairo_curve_to (cr,
  283. x_offset - ((i - 0.5f) * graph->graph_delx),
  284. (1.0f - graph->data[i-1][j]) * graph->real_draw_height + 3.5f,
  285. x_offset - ((i - 0.5f) * graph->graph_delx),
  286. (1.0f - graph->data[i][j]) * graph->real_draw_height + 3.5f,
  287. x_offset - (i * graph->graph_delx),
  288. (1.0f - graph->data[i][j]) * graph->real_draw_height + 3.5f);
  289. }
  290. cairo_stroke (cr);
  291.  
  292. }
  293.  
  294. cairo_destroy (cr);
  295.  
  296. return TRUE;
  297. }
  298.  
  299. static void
  300. get_load (LoadGraph *graph)
  301. {
  302. guint i;
  303. glibtop_cpu cpu;
  304.  
  305. glibtop_get_cpu (&cpu);
  306.  
  307. #undef NOW
  308. #undef LAST
  309. #define NOW (graph->cpu.times[graph->cpu.now])
  310. #define LAST (graph->cpu.times[graph->cpu.now ^ 1])
  311.  
  312. if (graph->n == 1) {
  313. NOW[0][CPU_TOTAL] = cpu.total;
  314. NOW[0][CPU_USED] = cpu.user + cpu.nice + cpu.sys;
  315. } else {
  316. for (i = 0; i < graph->n; i++) {
  317. NOW[i][CPU_TOTAL] = cpu.xcpu_total[i];
  318. NOW[i][CPU_USED] = cpu.xcpu_user[i] + cpu.xcpu_nice[i]
  319. + cpu.xcpu_sys[i];
  320. }
  321. }
  322.  
  323. // on the first call, LAST is 0
  324. // which means data is set to the average load since boot
  325. // that value has no meaning, we just want all the
  326. // graphs to be aligned, so the CPU graph needs to start
  327. // immediately
  328.  
  329. for (i = 0; i < graph->n; i++) {
  330. float load;
  331. float total, used;
  332. gchar *text;
  333.  
  334. total = NOW[i][CPU_TOTAL] - LAST[i][CPU_TOTAL];
  335. used = NOW[i][CPU_USED] - LAST[i][CPU_USED];
  336.  
  337. load = used / MAX(total, 1.0f);
  338. graph->data[0][i] = load;
  339.  
  340. /* Update label */
  341. text = g_strdup_printf("%.1f%%", load * 100.0f);
  342. gtk_label_set_text(GTK_LABEL(graph->labels.cpu[i]), text);
  343. g_free(text);
  344. }
  345.  
  346. graph->cpu.now ^= 1;
  347.  
  348. #undef NOW
  349. #undef LAST
  350. }
  351.  
  352.  
  353. namespace
  354. {
  355.  
  356. void set_memory_label_and_picker(GtkLabel* label, GSMColorButton* picker,
  357. guint64 used, guint64 total, double percent)
  358. {
  359. char* used_text;
  360. char* total_text;
  361. char* text;
  362.  
  363. used_text = procman::format_size(used);
  364. total_text = procman::format_size(total);
  365. if (total == 0) {
  366. text = g_strdup(_("not available"));
  367. } else {
  368. // xgettext: 540MiB (53 %) of 1.0 GiB
  369. text = g_strdup_printf(_("%s (%.1f%%) of %s"), used_text, 100.0 * percent, total_text);
  370. }
  371. gtk_label_set_text(label, text);
  372. g_free(used_text);
  373. g_free(total_text);
  374. g_free(text);
  375.  
  376. if (picker)
  377. gsm_color_button_set_fraction(picker, percent);
  378. }
  379. }
  380.  
  381. static void
  382. get_memory (LoadGraph *graph)
  383. {
  384. float mempercent, swappercent;
  385.  
  386. glibtop_mem mem;
  387. glibtop_swap swap;
  388.  
  389. glibtop_get_mem (&mem);
  390. glibtop_get_swap (&swap);
  391.  
  392. /* There's no swap on LiveCD : 0.0f is better than NaN :) */
  393. swappercent = (swap.total ? (float)swap.used / (float)swap.total : 0.0f);
  394. mempercent = (float)mem.user / (float)mem.total;
  395.  
  396. set_memory_label_and_picker(GTK_LABEL(graph->labels.memory),
  397. GSM_COLOR_BUTTON(graph->mem_color_picker),
  398. mem.user, mem.total, mempercent);
  399.  
  400. set_memory_label_and_picker(GTK_LABEL(graph->labels.swap),
  401. GSM_COLOR_BUTTON(graph->swap_color_picker),
  402. swap.used, swap.total, swappercent);
  403.  
  404. graph->data[0][0] = mempercent;
  405. graph->data[0][1] = swappercent;
  406. }
  407.  
  408. /* Nice Numbers for Graph Labels after Paul Heckbert
  409. nicenum: find a "nice" number approximately equal to x.
  410. Round the number if round=1, take ceiling if round=0 */
  411.  
  412. static double
  413. nicenum (double x, int round)
  414. {
  415. int expv; /* exponent of x */
  416. double f; /* fractional part of x */
  417. double nf; /* nice, rounded fraction */
  418.  
  419. expv = floor(log10(x));
  420. f = x/pow(10.0, expv); /* between 1 and 10 */
  421. if (round) {
  422. if (f < 1.5)
  423. nf = 1.0;
  424. else if (f < 3.0)
  425. nf = 2.0;
  426. else if (f < 7.0)
  427. nf = 5.0;
  428. else
  429. nf = 10.0;
  430. } else {
  431. if (f <= 1.0)
  432. nf = 1.0;
  433. else if (f <= 2.0)
  434. nf = 2.0;
  435. else if (f <= 5.0)
  436. nf = 5.0;
  437. else
  438. nf = 10.0;
  439. }
  440. return nf * pow(10.0, expv);
  441. }
  442.  
  443. static void
  444. net_scale (LoadGraph *graph, guint64 din, guint64 dout)
  445. {
  446. graph->data[0][0] = 1.0f * din / graph->net.max;
  447. graph->data[0][1] = 1.0f * dout / graph->net.max;
  448.  
  449. guint64 dmax = std::max(din, dout);
  450. graph->net.values[graph->net.cur] = dmax;
  451. graph->net.cur = (graph->net.cur + 1) % LoadGraph::NUM_POINTS;
  452.  
  453. guint64 new_max;
  454. // both way, new_max is the greatest value
  455. if (dmax >= graph->net.max)
  456. new_max = dmax;
  457. else
  458. new_max = *std::max_element(&graph->net.values[0],
  459. &graph->net.values[LoadGraph::NUM_POINTS]);
  460.  
  461. //
  462. // Round network maximum
  463. //
  464.  
  465. const guint64 bak_max(new_max);
  466.  
  467. if (ProcData::get_instance()->config.network_in_bits) {
  468. // nice number is for the ticks
  469. unsigned ticks = graph->num_bars();
  470.  
  471. // gets messy at low values due to division by 8
  472. guint64 bit_max = std::max( new_max*8, G_GUINT64_CONSTANT(10000) );
  473.  
  474. // our tick size leads to max
  475. double d = nicenum(bit_max/ticks, 0);
  476. bit_max = ticks * d;
  477. new_max = bit_max / 8;
  478.  
  479. procman_debug("bak*8 %" G_GUINT64_FORMAT ", ticks %d, d %f"
  480. ", bit_max %" G_GUINT64_FORMAT ", new_max %" G_GUINT64_FORMAT,
  481. bak_max*8, ticks, d, bit_max, new_max );
  482. } else {
  483. // round up to get some extra space
  484. // yes, it can overflow
  485. new_max = 1.1 * new_max;
  486. // make sure max is not 0 to avoid / 0
  487. // default to 1 KiB
  488. new_max = std::max(new_max, G_GUINT64_CONSTANT(1024));
  489.  
  490. // decompose new_max = coef10 * 2**(base10 * 10)
  491. // where coef10 and base10 are integers and coef10 < 2**10
  492. //
  493. // e.g: ceil(100.5 KiB) = 101 KiB = 101 * 2**(1 * 10)
  494. // where base10 = 1, coef10 = 101, pow2 = 16
  495.  
  496. guint64 pow2 = std::floor(log2(new_max));
  497. guint64 base10 = pow2 / 10.0;
  498. guint64 coef10 = std::ceil(new_max / double(G_GUINT64_CONSTANT(1) << (base10 * 10)));
  499. g_assert(new_max <= (coef10 * (G_GUINT64_CONSTANT(1) << (base10 * 10))));
  500.  
  501. // then decompose coef10 = x * 10**factor10
  502. // where factor10 is integer and x < 10
  503. // so we new_max has only 1 significant digit
  504.  
  505. guint64 factor10 = std::pow(10.0, std::floor(std::log10(coef10)));
  506. coef10 = std::ceil(coef10 / double(factor10)) * factor10;
  507.  
  508. // then make coef10 divisible by num_bars
  509. if (coef10 % graph->num_bars() != 0)
  510. coef10 = coef10 + (graph->num_bars() - coef10 % graph->num_bars());
  511. g_assert(coef10 % graph->num_bars() == 0);
  512. new_max = coef10 * (G_GUINT64_CONSTANT(1) << guint64(base10 * 10));
  513. procman_debug("bak %" G_GUINT64_FORMAT " new_max %" G_GUINT64_FORMAT
  514. "pow2 %" G_GUINT64_FORMAT " coef10 %" G_GUINT64_FORMAT,
  515. bak_max, new_max, pow2, coef10);
  516. }
  517.  
  518. if (bak_max > new_max) {
  519. procman_debug("overflow detected: bak=%" G_GUINT64_FORMAT
  520. " new=%" G_GUINT64_FORMAT,
  521. bak_max, new_max);
  522. new_max = bak_max;
  523. }
  524.  
  525. // if max is the same or has decreased but not so much, don't
  526. // do anything to avoid rescaling
  527. if ((0.8 * graph->net.max) < new_max && new_max <= graph->net.max)
  528. return;
  529.  
  530. const double scale = 1.0f * graph->net.max / new_max;
  531.  
  532. for (size_t i = 0; i < LoadGraph::NUM_POINTS; i++) {
  533. if (graph->data[i][0] >= 0.0f) {
  534. graph->data[i][0] *= scale;
  535. graph->data[i][1] *= scale;
  536. }
  537. }
  538.  
  539. procman_debug("rescale dmax = %" G_GUINT64_FORMAT
  540. " max = %" G_GUINT64_FORMAT
  541. " new_max = %" G_GUINT64_FORMAT,
  542. dmax, graph->net.max, new_max);
  543.  
  544. graph->net.max = new_max;
  545.  
  546. // force the graph background to be redrawn now that scale has changed
  547. graph->clear_background();
  548. }
  549.  
  550. static void
  551. get_net (LoadGraph *graph)
  552. {
  553. glibtop_netlist netlist;
  554. char **ifnames;
  555. guint32 i;
  556. guint64 in = 0, out = 0;
  557. GTimeVal time;
  558. guint64 din, dout;
  559.  
  560. ifnames = glibtop_get_netlist(&netlist);
  561.  
  562. for (i = 0; i < netlist.number; ++i)
  563. {
  564. glibtop_netload netload;
  565. glibtop_get_netload (&netload, ifnames[i]);
  566.  
  567. if (netload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK))
  568. continue;
  569.  
  570. /* Skip interfaces without any IPv4/IPv6 address (or
  571. those with only a LINK ipv6 addr) However we need to
  572. be able to exclude these while still keeping the
  573. value so when they get online (with NetworkManager
  574. for example) we don't get a suddent peak. Once we're
  575. able to get this, ignoring down interfaces will be
  576. possible too. */
  577. if (not (netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS6)
  578. and netload.scope6 != GLIBTOP_IF_IN6_SCOPE_LINK)
  579. and not (netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS)))
  580. continue;
  581.  
  582. /* Don't skip interfaces that are down (GLIBTOP_IF_FLAGS_UP)
  583. to avoid spikes when they are brought up */
  584.  
  585. in += netload.bytes_in;
  586. out += netload.bytes_out;
  587. }
  588.  
  589. g_strfreev(ifnames);
  590.  
  591. g_get_current_time (&time);
  592.  
  593. if (in >= graph->net.last_in && out >= graph->net.last_out && graph->net.time.tv_sec != 0) {
  594. float dtime;
  595. dtime = time.tv_sec - graph->net.time.tv_sec +
  596. (double) (time.tv_usec - graph->net.time.tv_usec) / G_USEC_PER_SEC;
  597. din = static_cast<guint64>((in - graph->net.last_in) / dtime);
  598. dout = static_cast<guint64>((out - graph->net.last_out) / dtime);
  599. } else {
  600. /* Don't calc anything if new data is less than old (interface
  601. removed, counters reset, ...) or if it is the first time */
  602. din = 0;
  603. dout = 0;
  604. }
  605.  
  606. graph->net.last_in = in;
  607. graph->net.last_out = out;
  608. graph->net.time = time;
  609.  
  610. net_scale(graph, din, dout);
  611.  
  612. gtk_label_set_text (GTK_LABEL (graph->labels.net_in), procman::format_network_rate(din).c_str());
  613. gtk_label_set_text (GTK_LABEL (graph->labels.net_in_total), procman::format_network(in).c_str());
  614.  
  615. gtk_label_set_text (GTK_LABEL (graph->labels.net_out), procman::format_network_rate(dout).c_str());
  616. gtk_label_set_text (GTK_LABEL (graph->labels.net_out_total), procman::format_network(out).c_str());
  617. }
  618.  
  619.  
  620. /* Updates the load graph when the timeout expires */
  621. static gboolean
  622. load_graph_update (gpointer user_data)
  623. {
  624. LoadGraph * const graph = static_cast<LoadGraph*>(user_data);
  625.  
  626. if (graph->render_counter == graph->frames_per_unit - 1) {
  627. std::rotate(&graph->data[0],
  628. &graph->data[LoadGraph::NUM_POINTS - 1],
  629. &graph->data[LoadGraph::NUM_POINTS]);
  630.  
  631. switch (graph->type) {
  632. case LOAD_GRAPH_CPU:
  633. get_load(graph);
  634. break;
  635. case LOAD_GRAPH_MEM:
  636. get_memory(graph);
  637. break;
  638. case LOAD_GRAPH_NET:
  639. get_net(graph);
  640. break;
  641. default:
  642. g_assert_not_reached();
  643. }
  644. }
  645.  
  646. if (graph->draw)
  647. load_graph_queue_draw (graph);
  648.  
  649. graph->render_counter++;
  650.  
  651. if (graph->render_counter >= graph->frames_per_unit)
  652. graph->render_counter = 0;
  653.  
  654. return TRUE;
  655. }
  656.  
  657.  
  658.  
  659. LoadGraph::~LoadGraph()
  660. {
  661. load_graph_stop(this);
  662.  
  663. if (timer_index)
  664. g_source_remove(timer_index);
  665.  
  666. clear_background();
  667. }
  668.  
  669.  
  670.  
  671. static gboolean
  672. load_graph_destroy (GtkWidget *widget, gpointer data_ptr)
  673. {
  674. LoadGraph * const graph = static_cast<LoadGraph*>(data_ptr);
  675.  
  676. delete graph;
  677.  
  678. return FALSE;
  679. }
  680.  
  681.  
  682. LoadGraph::LoadGraph(guint type)
  683. : fontsize(8.0),
  684. rmargin(3.5 * fontsize),
  685. indent(24.0),
  686. n(0),
  687. type(type),
  688. speed(0),
  689. draw_width(0),
  690. draw_height(0),
  691. render_counter(0),
  692. frames_per_unit(10), // this will be changed but needs initialising
  693. graph_dely(0),
  694. real_draw_height(0),
  695. graph_delx(0.0),
  696. graph_buffer_offset(0),
  697. main_widget(NULL),
  698. disp(NULL),
  699. background(NULL),
  700. timer_index(0),
  701. draw(FALSE),
  702. mem_color_picker(NULL),
  703. swap_color_picker(NULL)
  704. {
  705. LoadGraph * const graph = this;
  706.  
  707. // FIXME:
  708. // on configure, graph->frames_per_unit = graph->draw_width/(LoadGraph::NUM_POINTS);
  709. // knock FRAMES down to 5 until cairo gets faster
  710.  
  711. switch (type) {
  712. case LOAD_GRAPH_CPU:
  713. memset(&cpu, 0, sizeof cpu);
  714. n = ProcData::get_instance()->config.num_cpus;
  715.  
  716. for(guint i = 0; i < G_N_ELEMENTS(labels.cpu); ++i)
  717. labels.cpu[i] = gtk_label_new(NULL);
  718.  
  719. break;
  720.  
  721. case LOAD_GRAPH_MEM:
  722. n = 2;
  723. labels.memory = gtk_label_new(NULL);
  724. gtk_misc_set_alignment (GTK_MISC (labels.memory), 0.0, 0.5);
  725. labels.swap = gtk_label_new(NULL);
  726. gtk_misc_set_alignment (GTK_MISC (labels.swap), 0.0, 0.5);
  727. break;
  728.  
  729. case LOAD_GRAPH_NET:
  730. memset(&net, 0, sizeof net);
  731. n = 2;
  732. net.max = 1;
  733. labels.net_in = gtk_label_new(NULL);
  734. gtk_label_set_width_chars(GTK_LABEL(labels.net_in), 15);
  735. gtk_misc_set_alignment (GTK_MISC (labels.net_in), 1.0, 0.5);
  736. labels.net_in_total = gtk_label_new(NULL);
  737. gtk_misc_set_alignment (GTK_MISC (labels.net_in_total), 1.0, 0.5);
  738. gtk_label_set_width_chars(GTK_LABEL(labels.net_in_total), 15);
  739. labels.net_out = gtk_label_new(NULL);
  740. gtk_misc_set_alignment (GTK_MISC (labels.net_out), 1.0, 0.5);
  741. gtk_label_set_width_chars(GTK_LABEL(labels.net_out), 15);
  742. labels.net_out_total = gtk_label_new(NULL);
  743. gtk_misc_set_alignment (GTK_MISC (labels.net_out_total), 1.0, 0.5);
  744. gtk_label_set_width_chars(GTK_LABEL(labels.net_out_total), 15);
  745. break;
  746. }
  747.  
  748. speed = ProcData::get_instance()->config.graph_update_interval;
  749.  
  750. colors.resize(n);
  751.  
  752. switch (type) {
  753. case LOAD_GRAPH_CPU:
  754. memcpy(&colors[0], ProcData::get_instance()->config.cpu_color,
  755. n * sizeof colors[0]);
  756. break;
  757. case LOAD_GRAPH_MEM:
  758. colors[0] = ProcData::get_instance()->config.mem_color;
  759. colors[1] = ProcData::get_instance()->config.swap_color;
  760. mem_color_picker = gsm_color_button_new (&colors[0],
  761. GSMCP_TYPE_PIE);
  762. swap_color_picker = gsm_color_button_new (&colors[1],
  763. GSMCP_TYPE_PIE);
  764. break;
  765. case LOAD_GRAPH_NET:
  766. colors[0] = ProcData::get_instance()->config.net_in_color;
  767. colors[1] = ProcData::get_instance()->config.net_out_color;
  768. break;
  769. }
  770.  
  771. timer_index = 0;
  772. render_counter = (frames_per_unit - 1);
  773. draw = FALSE;
  774.  
  775. main_widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
  776. gtk_widget_set_size_request(main_widget, -1, LoadGraph::GRAPH_MIN_HEIGHT);
  777. gtk_widget_show (main_widget);
  778.  
  779. disp = gtk_drawing_area_new ();
  780. gtk_widget_show (disp);
  781. g_signal_connect (G_OBJECT (disp), "draw",
  782. G_CALLBACK (load_graph_draw), graph);
  783. g_signal_connect (G_OBJECT(disp), "configure_event",
  784. G_CALLBACK (load_graph_configure), graph);
  785. g_signal_connect (G_OBJECT(disp), "destroy",
  786. G_CALLBACK (load_graph_destroy), graph);
  787.  
  788. gtk_widget_set_events (disp, GDK_EXPOSURE_MASK);
  789.  
  790. gtk_box_pack_start (GTK_BOX (main_widget), disp, TRUE, TRUE, 0);
  791.  
  792.  
  793. /* Allocate data in a contiguous block */
  794. data_block = std::vector<float>(n * LoadGraph::NUM_POINTS, -1.0f);
  795.  
  796. for (guint i = 0; i < LoadGraph::NUM_POINTS; ++i)
  797. data[i] = &data_block[0] + i * n;
  798.  
  799. gtk_widget_show_all (main_widget);
  800. }
  801.  
  802. void
  803. load_graph_start (LoadGraph *graph)
  804. {
  805. if (!graph->timer_index) {
  806.  
  807. load_graph_update(graph);
  808.  
  809. graph->timer_index = g_timeout_add (graph->speed / graph->frames_per_unit,
  810. load_graph_update,
  811. graph);
  812. }
  813.  
  814. graph->draw = TRUE;
  815. }
  816.  
  817. void
  818. load_graph_stop (LoadGraph *graph)
  819. {
  820. /* don't draw anymore, but continue to poll */
  821. graph->draw = FALSE;
  822. }
  823.  
  824. void
  825. load_graph_change_speed (LoadGraph *graph,
  826. guint new_speed)
  827. {
  828. if (graph->speed == new_speed)
  829. return;
  830.  
  831. graph->speed = new_speed;
  832.  
  833. if (graph->timer_index) {
  834. g_source_remove (graph->timer_index);
  835. graph->timer_index = g_timeout_add (graph->speed / graph->frames_per_unit,
  836. load_graph_update,
  837. graph);
  838. }
  839.  
  840. graph->clear_background();
  841. }
  842.  
  843.  
  844. LoadGraphLabels*
  845. load_graph_get_labels (LoadGraph *graph)
  846. {
  847. return &graph->labels;
  848. }
  849.  
  850. GtkWidget*
  851. load_graph_get_widget (LoadGraph *graph)
  852. {
  853. return graph->main_widget;
  854. }
  855.  
  856. GtkWidget*
  857. load_graph_get_mem_color_picker(LoadGraph *graph)
  858. {
  859. return graph->mem_color_picker;
  860. }
  861.  
  862. GtkWidget*
  863. load_graph_get_swap_color_picker(LoadGraph *graph)
  864. {
  865. return graph->swap_color_picker;
  866. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement