1 /* Metageek WiSPY interface
2 * Mike Kershaw/Dragorn <dragorn@kismetwireless.net>
3 *
4 * This code is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This code is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * Extra thanks to Ryan Woodings @ Metageek for interface documentation
15 */
16
17 #include <math.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "spectool_gtk_spectral.h"
23
24 char spectral_help_txt[] =
25 "<b>Spectral View</b>\n\n"
26 "\"Waterfall\" style view over time showing the peak spectrum usage for each "
27 "time slice.";
28
29 /* Default set of colors inherited from the old spectool_gtk code */
30 float spect_default_colormap[] = {
31 HC2CC(0x00), HC2CC(0x45), HC2CC(0xFE),
32 HC2CC(0x00), HC2CC(0x5C), HC2CC(0xFE),
33 HC2CC(0x00), HC2CC(0x73), HC2CC(0xFE),
34 HC2CC(0x00), HC2CC(0x8A), HC2CC(0xFE),
35 HC2CC(0x00), HC2CC(0xA1), HC2CC(0xFE),
36 HC2CC(0x00), HC2CC(0xB8), HC2CC(0xFE),
37 HC2CC(0x00), HC2CC(0xCF), HC2CC(0xFE),
38 HC2CC(0x00), HC2CC(0xE6), HC2CC(0xFE),
39 HC2CC(0x1A), HC2CC(0xEB), HC2CC(0xCB),
40 HC2CC(0x33), HC2CC(0xF0), HC2CC(0x98),
41 HC2CC(0x4D), HC2CC(0xF5), HC2CC(0x66),
42 HC2CC(0x66), HC2CC(0xFA), HC2CC(0x33),
43 HC2CC(0x80), HC2CC(0xFF), HC2CC(0x00),
44 HC2CC(0x99), HC2CC(0xF5), HC2CC(0x00),
45 HC2CC(0xB3), HC2CC(0xEA), HC2CC(0x00),
46 HC2CC(0xCC), HC2CC(0xE0), HC2CC(0x00),
47 HC2CC(0xE6), HC2CC(0xD5), HC2CC(0x00),
48 HC2CC(0xFF), HC2CC(0xCB), HC2CC(0x00),
49 HC2CC(0xFF), HC2CC(0xBC), HC2CC(0x00),
50 HC2CC(0xFF), HC2CC(0xAD), HC2CC(0x00),
51 HC2CC(0xFF), HC2CC(0x9E), HC2CC(0x00),
52 HC2CC(0xFF), HC2CC(0x8F), HC2CC(0x00),
53 HC2CC(0xFF), HC2CC(0x80), HC2CC(0x00),
54 HC2CC(0xFF), HC2CC(0x74), HC2CC(0x0E),
55 HC2CC(0xFF), HC2CC(0x68), HC2CC(0x1C),
56 HC2CC(0xFF), HC2CC(0x5D), HC2CC(0x29),
57 HC2CC(0xFF), HC2CC(0x51), HC2CC(0x37),
58 HC2CC(0xFF), HC2CC(0x45), HC2CC(0x45),
59 HC2CC(0xFF), HC2CC(0x39), HC2CC(0x53),
60 HC2CC(0xFF), HC2CC(0x2D), HC2CC(0x61),
61 HC2CC(0xFF), HC2CC(0x25), HC2CC(0x65)
62 };
63 int spect_default_colormap_len = 31;
64
65 float spect_21_colormap[] = {
66 HC2CC(0x00), HC2CC(0x00), HC2CC(0x00),
67 HC2CC(0), HC2CC(0), HC2CC(46),
68 HC2CC(0), HC2CC(0), HC2CC(51),
69 HC2CC(0), HC2CC(5), HC2CC(55),
70 HC2CC(0), HC2CC(10), HC2CC(60),
71 HC2CC(0), HC2CC(16), HC2CC(64),
72 HC2CC(0), HC2CC(23), HC2CC(68),
73 HC2CC(0), HC2CC(30), HC2CC(72),
74 HC2CC(0), HC2CC(38), HC2CC(77),
75 HC2CC(0), HC2CC(47), HC2CC(81),
76 HC2CC(0), HC2CC(57), HC2CC(85),
77 HC2CC(0), HC2CC(67), HC2CC(89),
78 HC2CC(0), HC2CC(78), HC2CC(94),
79 HC2CC(0), HC2CC(90), HC2CC(98),
80 HC2CC(0), HC2CC(102), HC2CC(102),
81 HC2CC(0), HC2CC(106), HC2CC(97),
82 HC2CC(0), HC2CC(111), HC2CC(92),
83 HC2CC(0), HC2CC(115), HC2CC(86),
84 HC2CC(0), HC2CC(119), HC2CC(79),
85 HC2CC(0), HC2CC(123), HC2CC(72),
86 HC2CC(0), HC2CC(128), HC2CC(64),
87 HC2CC(0), HC2CC(132), HC2CC(55),
88 HC2CC(0), HC2CC(136), HC2CC(45),
89 HC2CC(0), HC2CC(140), HC2CC(35),
90 HC2CC(0), HC2CC(145), HC2CC(24),
91 HC2CC(0), HC2CC(149), HC2CC(12),
92 HC2CC(0), HC2CC(153), HC2CC(0),
93 HC2CC(13), HC2CC(157), HC2CC(0),
94 HC2CC(27), HC2CC(162), HC2CC(0),
95 HC2CC(41), HC2CC(166), HC2CC(0),
96 HC2CC(57), HC2CC(170), HC2CC(0),
97 HC2CC(73), HC2CC(174), HC2CC(0),
98 HC2CC(89), HC2CC(179), HC2CC(0),
99 HC2CC(107), HC2CC(183), HC2CC(0),
100 HC2CC(125), HC2CC(187), HC2CC(0),
101 HC2CC(143), HC2CC(191), HC2CC(0),
102 HC2CC(163), HC2CC(195), HC2CC(0),
103 HC2CC(183), HC2CC(200), HC2CC(0),
104 HC2CC(204), HC2CC(204), HC2CC(0),
105 HC2CC(208), HC2CC(191), HC2CC(0),
106 HC2CC(212), HC2CC(177), HC2CC(0),
107 HC2CC(217), HC2CC(163), HC2CC(0),
108 HC2CC(221), HC2CC(147), HC2CC(0),
109 HC2CC(225), HC2CC(131), HC2CC(0),
110 HC2CC(229), HC2CC(115), HC2CC(0),
111 HC2CC(234), HC2CC(97), HC2CC(0),
112 HC2CC(238), HC2CC(79), HC2CC(0),
113 HC2CC(242), HC2CC(61), HC2CC(0),
114 HC2CC(246), HC2CC(41), HC2CC(0),
115 HC2CC(251), HC2CC(21), HC2CC(0),
116 HC2CC(255), HC2CC(0), HC2CC(0)
117 };
118 int spect_21_colormap_len = 50;
119
120 static void spectool_spectral_class_init(SpectoolSpectralClass *class);
121 static void spectool_spectral_init(SpectoolSpectral *graph);
122 static void spectool_spectral_destroy(GtkObject *object);
123
124 static gint spectool_spectral_configure(GtkWidget *widget,
125 GdkEventConfigure *event);
126
127 G_DEFINE_TYPE(SpectoolSpectral, spectool_spectral, SPECTOOL_TYPE_WIDGET);
128
spectool_spectral_draw(GtkWidget * widget,cairo_t * cr,SpectoolWidget * wwidget)129 void spectool_spectral_draw(GtkWidget *widget, cairo_t *cr, SpectoolWidget *wwidget) {
130 SpectoolSpectral *spectral;
131 int nsamp, pos, sp;
132 int sh, b_s_y;
133 cairo_pattern_t *pattern;
134 cairo_matrix_t matrix;
135 GdkPixmap *linemap;
136 GdkColormap *cmap = gdk_colormap_get_system();
137 cairo_t *lcr;
138
139 g_return_if_fail(widget != NULL);
140
141 spectral = SPECTOOL_SPECTRAL(wwidget);
142
143 cairo_save(cr);
144
145 /* Figure out the height mod our number of samples... wwidget->wbar is
146 * the width of each rectangle */
147 sh = (double) wwidget->g_len_y / wwidget->sweepcache->num_alloc;
148
149 if (sh < 3)
150 sh = 3;
151 else
152 sh = sh + 1;
153
154 /* Plot across for each sample, with funny looping to handle the
155 * ring allocation. The oldest sample is the first non-null sample
156 * after the current position. We want to go back /drawable/ samples,
157 * so hack in a smarter decrement based on how we know the ring works.
158 * Probably an ugly way of doing it. */
159 if (wwidget->sweepcache->pos >= (wwidget->g_len_y / sh)) {
160 nsamp = wwidget->sweepcache->pos - (wwidget->g_len_y / sh);
161 } else if (wwidget->sweepcache->sweeplist[wwidget->sweepcache->num_alloc - 1] !=
162 NULL) {
163 nsamp = wwidget->sweepcache->num_alloc - ((wwidget->g_len_y / sh) -
164 wwidget->sweepcache->pos);
165 } else {
166 nsamp = 0;
167 }
168
169 /* Catch rounding errors and other silliness */
170 if (nsamp < 0)
171 nsamp = 0;
172
173 pos = 0;
174 while (nsamp != wwidget->sweepcache->pos &&
175 pos <= wwidget->sweepcache->num_alloc) {
176 spectool_sample_sweep *samp;
177
178 /* Loop around the ring */
179 if (nsamp >= wwidget->sweepcache->num_alloc)
180 nsamp = 0;
181
182 /* Skip empty allocations in the ring */
183 if (wwidget->sweepcache->sweeplist[nsamp] == NULL) {
184 nsamp++;
185 continue;
186 }
187
188 /* Skip ones too old to be seen */
189 if (sh * pos > wwidget->g_len_y) {
190 break;
191 }
192
193 /* Thrash out if we're outside our cache bounds, but it shouldn't
194 * happen */
195 if (nsamp < 0 || nsamp >= spectral->line_cache_len) {
196 printf("debug - outside of cache range! %d, cache %d\n",
197 nsamp, spectral->line_cache_len);
198 return;
199 }
200
201 if (spectral->line_cache[nsamp] == NULL) {
202 /* Current sample */
203 samp = wwidget->sweepcache->sweeplist[nsamp];
204
205 linemap = gdk_pixmap_new(NULL, wwidget->g_len_x, sh,
206 cmap->visual->depth);
207 gdk_drawable_set_colormap(linemap, cmap);
208
209 /* Make a pattern for cairo to draw */
210 pattern =
211 cairo_pattern_create_linear(0, 0, wwidget->g_len_x, 0);
212 lcr = gdk_cairo_create(linemap);
213 cairo_rectangle(lcr, 0, 0, wwidget->g_len_x, sh);
214 cairo_clip(lcr);
215
216 for (sp = 0; sp < samp->num_samples - 1; sp++) {
217 int cpos;
218 int sdb =
219 SPECTOOL_RSSI_CONVERT(wwidget->amp_offset_mdbm, wwidget->amp_res_mdbm,
220 samp->sample_data[sp]);
221
222 cpos =
223 (float) (spectral->colormap_len) *
224 ((float) (abs(sdb) + wwidget->base_db_offset) /
225 (float) (abs(wwidget->min_db_draw) -
226 abs(wwidget->base_db_offset)));
227
228 if (cpos < 0)
229 cpos = 0;
230 else if (cpos >= spectral->colormap_len)
231 cpos = spectral->colormap_len - 1;
232
233 cpos = spectral->colormap_len - cpos;
234
235 /* Pattern add uses 0.0 - 1.0 for stop lengths so we have to calculate
236 * them that way */
237 cairo_pattern_add_color_stop_rgb(pattern,
238 (float) (sp) / (samp->num_samples - 1),
239 SPECTOOL_SPECTRAL_COLOR(spectral->colormap, cpos, 0),
240 SPECTOOL_SPECTRAL_COLOR(spectral->colormap, cpos, 1),
241 SPECTOOL_SPECTRAL_COLOR(spectral->colormap, cpos, 2));
242 }
243
244 /* Draw a line over our pixmap */
245 cairo_set_source(lcr, pattern);
246 cairo_rectangle(lcr, -1, -1, wwidget->g_len_x + 1, sh + 1);
247 cairo_fill(lcr);
248 cairo_destroy(lcr);
249 cairo_pattern_destroy(pattern);
250 spectral->line_cache[nsamp] = linemap;
251 }
252
253 /* Top position of the pixmap line, drawing from the bottom up */
254 b_s_y = wwidget->g_end_y - ((pos + 1) * sh);
255
256 gdk_cairo_set_source_pixmap(cr, spectral->line_cache[nsamp],
257 wwidget->g_start_x, b_s_y);
258 cairo_rectangle(cr, wwidget->g_start_x + 0.5, b_s_y + 0.5,
259 wwidget->g_len_x, sh + 1);
260 cairo_fill(cr);
261
262 nsamp++;
263 pos++;
264
265 }
266
267 cairo_restore(cr);
268 }
269
spectool_spectral_size_allocate(GtkWidget * widget,GtkAllocation * allocation)270 static void spectool_spectral_size_allocate(GtkWidget *widget,
271 GtkAllocation *allocation) {
272 SpectoolSpectral *spectral = SPECTOOL_SPECTRAL(widget);
273 int x;
274
275 GTK_WIDGET_CLASS(spectool_spectral_parent_class)->size_allocate(widget, allocation);
276
277 /* Wipe the line cache on resize */
278 if (allocation->width != spectral->oldx ||
279 allocation->height != spectral->oldy) {
280 spectral->oldx = allocation->width;
281 spectral->oldy = allocation->height;
282
283 if (spectral->line_cache != NULL) {
284 for (x = 0; x < spectral->line_cache_len; x++) {
285 if (spectral->line_cache[x] != NULL) {
286 gdk_pixmap_unref(spectral->line_cache[x]);
287 spectral->line_cache[x] = NULL;
288 }
289
290 }
291 }
292 }
293 }
294
spectool_spectral_class_init(SpectoolSpectralClass * class)295 static void spectool_spectral_class_init(SpectoolSpectralClass *class) {
296 GObjectClass *gobject_class;
297 GtkObjectClass *object_class;
298 GtkWidgetClass *widget_class;
299
300 gobject_class = G_OBJECT_CLASS(class);
301 object_class = GTK_OBJECT_CLASS(class);
302 widget_class = GTK_WIDGET_CLASS(class);
303
304 object_class->destroy = spectool_spectral_destroy;
305 widget_class->size_allocate = spectool_spectral_size_allocate;
306 }
307
spectool_spectral_destroy(GtkObject * object)308 static void spectool_spectral_destroy(GtkObject *object) {
309 SpectoolSpectral *spectral = SPECTOOL_SPECTRAL(object);
310 SpectoolWidget *wwidget;
311
312 wwidget = SPECTOOL_WIDGET(spectral);
313
314 GTK_OBJECT_CLASS(spectool_spectral_parent_class)->destroy(object);
315 }
316
spectool_spectral_wdr_devbind(GtkWidget * widget,spectool_device_registry * wdr,int slot)317 static void spectool_spectral_wdr_devbind(GtkWidget *widget, spectool_device_registry *wdr,
318 int slot) {
319 SpectoolSpectral *spectral;
320 SpectoolWidget *wwidget;
321
322 g_return_if_fail(widget != NULL);
323 g_return_if_fail(IS_SPECTOOL_SPECTRAL(widget));
324 g_return_if_fail(IS_SPECTOOL_WIDGET(widget));
325
326 spectral = SPECTOOL_SPECTRAL(widget);
327 wwidget = SPECTOOL_WIDGET(widget);
328 }
329
spectool_spectral_wdr_sweep(int slot,int mode,spectool_sample_sweep * sweep,void * aux)330 static void spectool_spectral_wdr_sweep(int slot, int mode,
331 spectool_sample_sweep *sweep,
332 void *aux) {
333 SpectoolSpectral *spectral;
334 SpectoolWidget *wwidget;
335 int x, tout;
336 spectool_phy *pd;
337
338 g_return_if_fail(aux != NULL);
339 g_return_if_fail(IS_SPECTOOL_SPECTRAL(aux));
340 g_return_if_fail(IS_SPECTOOL_WIDGET(aux));
341
342 spectral = SPECTOOL_SPECTRAL(aux);
343 wwidget = SPECTOOL_WIDGET(aux);
344
345 tout = wwidget->draw_timeout;
346
347 /* Update the timer */
348 if (sweep != NULL && sweep->phydev != NULL) {
349 pd = (spectool_phy *) sweep->phydev;
350 #ifdef HAVE_HILDON
351 tout = 500 * pd->draw_agg_suggestion;
352 #else
353 tout = 150 * pd->draw_agg_suggestion;
354 #endif
355 }
356
357 if (tout != wwidget->draw_timeout) {
358 wwidget->draw_timeout = tout;
359 g_source_remove(wwidget->timeout_ref);
360 wwidget->timeout_ref =
361 g_timeout_add(wwidget->draw_timeout,
362 (GSourceFunc) spectool_widget_timeout, wwidget);
363 }
364
365 if ((mode & SPECTOOL_POLL_CONFIGURED)) {
366 /* Allocate the cache of lines to draw */
367 if (spectral->line_cache != NULL) {
368 for (x = 0; x < spectral->line_cache_len; x++) {
369 if (spectral->line_cache[x] != NULL) {
370 gdk_pixmap_unref(spectral->line_cache[x]);
371 }
372
373 }
374 }
375 free(spectral->line_cache);
376
377 spectral->line_cache = malloc(sizeof(GdkPixmap *) *
378 wwidget->sweepcache->num_alloc);
379 spectral->line_cache_len = wwidget->sweepcache->num_alloc;
380 spectral->n_sweeps_delta = 0;
381
382 for (x = 0; x < spectral->line_cache_len; x++) {
383 spectral->line_cache[x] = NULL;
384 }
385 } else if ((mode & SPECTOOL_POLL_SWEEPCOMPLETE)) {
386 /* Null out this sweep in the cache so we have to recalculate it */
387 if (wwidget->sweepcache->pos >= 0 &&
388 wwidget->sweepcache->pos < spectral->line_cache_len) {
389 if (spectral->line_cache[wwidget->sweepcache->pos] != NULL)
390 gdk_pixmap_unref(spectral->line_cache[wwidget->sweepcache->pos]);
391 spectral->line_cache[wwidget->sweepcache->pos] = NULL;
392 }
393
394 spectral->n_sweeps_delta++;
395 }
396 }
397
spectool_spectral_new(void)398 GtkWidget *spectool_spectral_new(void) {
399 SpectoolSpectral *spectral;
400 SpectoolWidget *wwidget;
401
402 spectral = gtk_type_new(spectool_spectral_get_type());
403
404 wwidget = SPECTOOL_WIDGET(spectral);
405
406 return GTK_WIDGET(spectral);
407 }
408
spectool_spectral_legend_expose(GtkWidget * widget,GdkEventExpose * event,gpointer * aux)409 static gboolean spectool_spectral_legend_expose(GtkWidget *widget,
410 GdkEventExpose *event,
411 gpointer *aux) {
412 cairo_t *cr;
413 int x, y, w, h, dw, dh;
414 SpectoolSpectral *spectral;
415 cairo_pattern_t *pattern;
416 int cp;
417
418 g_return_val_if_fail(widget != NULL, FALSE);
419 g_return_val_if_fail(aux != NULL, FALSE);
420 g_return_val_if_fail(IS_SPECTOOL_SPECTRAL(aux), FALSE);
421
422 spectral = SPECTOOL_SPECTRAL(aux);
423
424 cr = gdk_cairo_create(widget->window);
425
426 if (event != NULL) {
427 x = event->area.x;
428 y = event->area.y;
429 w = event->area.width;
430 h = event->area.height;
431 } else {
432 x = 0;
433 y = 0;
434 w = widget->allocation.width;
435 h = widget->allocation.height;
436 }
437 dw = widget->allocation.width;
438 dh = widget->allocation.height;
439
440 cairo_rectangle(cr, x, y, w, h);
441
442 cairo_clip(cr);
443
444 pattern = cairo_pattern_create_linear(0, 0, dw, 0);
445
446 for (cp = 0; cp < spectral->colormap_len; cp++) {
447 cairo_pattern_add_color_stop_rgb(pattern,
448 (float) (cp) / (spectral->colormap_len),
449 SPECTOOL_SPECTRAL_COLOR(spectral->colormap, cp, 0),
450 SPECTOOL_SPECTRAL_COLOR(spectral->colormap, cp, 1),
451 SPECTOOL_SPECTRAL_COLOR(spectral->colormap, cp, 2));
452 }
453
454 cairo_set_source(cr, pattern);
455 cairo_rectangle(cr, -1, -1, dw + 1, dh + 1);
456 cairo_fill(cr);
457 cairo_pattern_destroy(pattern);
458
459 cairo_destroy(cr);
460
461 return FALSE;
462 }
463
spectool_spectral_context_help(gpointer * aux)464 void spectool_spectral_context_help(gpointer *aux) {
465 Spectool_Help_Dialog("Spectral View", spectral_help_txt);
466 }
467
spectool_spectral_init(SpectoolSpectral * spectral)468 static void spectool_spectral_init(SpectoolSpectral *spectral) {
469 SpectoolWidget *wwidget;
470
471 GtkWidget *temp;
472 GtkWidget *legendv, *legendh;
473 PangoAttrList *attr_list;
474 PangoAttribute *attr;
475
476 wwidget = SPECTOOL_WIDGET(spectral);
477
478 wwidget->sweep_num_samples = SPECTOOL_SPECTRAL_NUM_SAMPLES;
479 wwidget->sweep_keep_avg = 0;
480 wwidget->sweep_keep_peak = 0;
481
482 wwidget->sweep_num_aggregate = 3;
483
484 wwidget->hlines = 8;
485 wwidget->base_db_offset = -30;
486
487 wwidget->graph_title = strdup("<b>Spectral View</b>");
488 wwidget->graph_title_bg = strdup("#CC0000");
489 wwidget->graph_control_bg = strdup("#CCA0A0");
490
491 wwidget->show_channels = 0;
492 wwidget->show_dbm = 0;
493 wwidget->show_dbm_lines = 0;
494
495 wwidget->wdr_sweep_func = spectool_spectral_wdr_sweep;
496 wwidget->wdr_devbind_func = spectool_spectral_wdr_devbind;
497 wwidget->draw_mouse_move_func = NULL;
498 wwidget->draw_mouse_click_func = NULL;
499 #ifdef HAVE_HILDON
500 wwidget->draw_timeout = 1500;
501 #else
502 wwidget->draw_timeout = 500;
503 #endif
504 wwidget->draw_func = spectool_spectral_draw;
505
506 wwidget->menu_func = NULL;
507 wwidget->help_func = spectool_spectral_context_help;
508
509 spectral->colormap = spect_21_colormap;
510 spectral->colormap_len = spect_21_colormap_len;
511
512 wwidget->timeout_ref =
513 g_timeout_add(wwidget->draw_timeout,
514 (GSourceFunc) spectool_widget_timeout, wwidget);
515
516 spectool_widget_buildgui(wwidget);
517
518 temp = gtk_frame_new("Legend");
519 gtk_box_pack_start(GTK_BOX(wwidget->vbox), temp, FALSE, FALSE, 2);
520 legendv = gtk_vbox_new(FALSE, 2);
521 gtk_container_add(GTK_CONTAINER(temp), legendv);
522 gtk_widget_show(temp);
523
524 legendh = gtk_hbox_new(TRUE, 2);
525 gtk_box_pack_start(GTK_BOX(legendv), legendh, TRUE, TRUE, 0);
526
527 spectral->legend_pix = gtk_drawing_area_new();
528 gtk_box_pack_start(GTK_BOX(legendv), spectral->legend_pix, FALSE, FALSE, 2);
529 gtk_drawing_area_size(GTK_DRAWING_AREA(spectral->legend_pix), -1, 10);
530 gtk_signal_connect(GTK_OBJECT(spectral->legend_pix), "expose_event",
531 (GtkSignalFunc) spectool_spectral_legend_expose, spectral);
532
533 attr_list = pango_attr_list_new();
534 attr = pango_attr_size_new(7.0 * PANGO_SCALE);
535 attr->start_index = 0;
536 attr->end_index = 100;
537 pango_attr_list_insert(attr_list, attr);
538
539 temp = gtk_label_new("Min");
540 gtk_label_set_use_markup(GTK_LABEL(temp), FALSE);
541 gtk_label_set_use_underline(GTK_LABEL(temp), FALSE);
542 gtk_label_set_attributes(GTK_LABEL(temp), attr_list);
543 gtk_misc_set_alignment(GTK_MISC(temp), 0, 0.5);
544 gtk_box_pack_start(GTK_BOX(legendh), temp, TRUE, TRUE, 0);
545 gtk_widget_show(temp);
546
547 temp = gtk_label_new("Max");
548 gtk_label_set_use_markup(GTK_LABEL(temp), FALSE);
549 gtk_label_set_use_underline(GTK_LABEL(temp), FALSE);
550 gtk_label_set_attributes(GTK_LABEL(temp), attr_list);
551 gtk_misc_set_alignment(GTK_MISC(temp), 1, 0.5);
552 gtk_box_pack_start(GTK_BOX(legendh), temp, TRUE, TRUE, 0);
553 gtk_widget_show(temp);
554
555 pango_attr_list_unref(attr_list);
556
557 gtk_widget_show(legendv);
558 gtk_widget_show(legendh);
559 gtk_widget_show(spectral->legend_pix);
560
561 spectral->oldx = spectral->oldy = 0;
562 }
563
564