1 /* gtkknob.c - libwhy GtkKnob knob widget
2 *
3 * Copyright (C) 2008, 2010 Sean Bolton
4 *
5 * Parts of this code come from GTK+, both the library source and
6 * the example programs. Other bits come from gAlan 0.2.0,
7 * copyright (C) 1999 Tony Garnock-Jones.
8 *
9 * gtkknob-cairo_or_pixmap_selectable.c
10 *
11 * - This version requires GTK+ 2.0 or later.
12 * - This version can use fast but ugly server-side pixmaps to draw
13 * the knobs.
14 * - On GTK+ 2.8 or later, this can also use cairo to draw nice but
15 * relatively slower anti-aliased knobs.
16 * - On GTK+ 2.8 or later, cairo is the default, but this can be
17 * changed using the function gtk_knob_set_fast_rendering().
18 * -FIX- It would be nice to add a property "fast-rendering" that
19 * could be easily set....
20 *
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License as
23 * published by the Free Software Foundation; either version 2 of
24 * the License, or (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be
27 * useful, but WITHOUT ANY WARRANTY; without even the implied
28 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
29 * PURPOSE. See the GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public
32 * License along with this program; if not, write to the Free
33 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
34 * Boston, MA 02110-1301 USA.
35 */
36
37 #define _ISOC99_SOURCE
38 #define _BSD_SOURCE
39
40 #include <stdlib.h>
41 #include <string.h>
42 #include <math.h>
43 #include <gtk/gtk.h>
44
45 #include "gtkknob.h"
46
47 #define KNOB_SIZE 32
48 #define HALF_KNOB_SIZE (KNOB_SIZE / 2)
49
50 #define UPDATE_DELAY_LENGTH 300
51
52
53 enum {
54 STATE_IDLE,
55 STATE_PRESSED,
56 STATE_DRAGGING
57 };
58
59 static GtkWidgetClass *parent_class = NULL;
60
61 #if GTK_CHECK_VERSION(2, 8, 0)
62 static int prefer_cairo = TRUE;
63 #else /* GTK_CHECK_VERSION(2, 8, 0) */
64 static int prefer_cairo = FALSE;
65 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
66
67 static struct {
68 int refcount;
69 GdkPixmap *pixmap;
70 GdkPixmap *insensitive_pixmap;
71 GdkBitmap *mask;
72 GdkGC *mask_gc;
73 GdkGC *red_gc;
74 #if GTK_CHECK_VERSION(2, 8, 0)
75 cairo_surface_t *knob_surface;
76 cairo_surface_t *insensitive_knob_surface;
77 cairo_pattern_t *shadow_pattern;
78 #endif
79 } common;
80
81 G_DEFINE_TYPE (GtkKnob, gtk_knob, GTK_TYPE_WIDGET);
82
83 static void gtk_knob_class_init (GtkKnobClass *klass);
84 static void gtk_knob_init (GtkKnob *knob);
85 static void gtk_knob_destroy (GtkObject *object);
86 static void gtk_knob_finalize (GObject *object);
87 static void gtk_knob_realize (GtkWidget *widget);
88 static void gtk_knob_size_request (GtkWidget *widget, GtkRequisition *requisition);
89 static void gtk_knob_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
90 static gint gtk_knob_button_press (GtkWidget *widget, GdkEventButton *event);
91 static gint gtk_knob_button_release(GtkWidget *widget, GdkEventButton *event);
92 static gint gtk_knob_motion_notify (GtkWidget *widget, GdkEventMotion *event);
93 static gint gtk_knob_timer_callback(GtkKnob *knob);
94 static void gtk_knob_update_mouse (GtkKnob *knob, gint x, gint y, gboolean absolute);
95 static void gtk_knob_adjustment_value_changed (GtkAdjustment *adjustment,
96 gpointer data);
97 static void gtk_knob_adjustment_changed (GtkAdjustment *adjustment,
98 gpointer data);
99 static gboolean gtk_knob_expose (GtkWidget *knob, GdkEventExpose *event);
100 static void gtk_knob_common_initialize(GtkWidget *widget);
101 static void gtk_knob_common_finalize(void);
102
103
104 static void
gtk_knob_class_init(GtkKnobClass * class)105 gtk_knob_class_init (GtkKnobClass *class)
106 {
107 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
108 GtkObjectClass *object_class = (GtkObjectClass*) class;
109 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
110
111 parent_class = g_type_class_peek_parent (class);
112
113 gobject_class->finalize = gtk_knob_finalize;
114 object_class->destroy = gtk_knob_destroy;
115
116 widget_class->realize = gtk_knob_realize;
117 widget_class->size_request = gtk_knob_size_request;
118 widget_class->size_allocate = gtk_knob_size_allocate;
119 widget_class->expose_event = gtk_knob_expose;
120 widget_class->button_press_event = gtk_knob_button_press;
121 widget_class->button_release_event = gtk_knob_button_release;
122 widget_class->motion_notify_event = gtk_knob_motion_notify;
123
124 common.refcount = 0;
125 common.pixmap = NULL;
126 common.insensitive_pixmap = NULL;
127 common.mask = NULL;
128 common.mask_gc = NULL;
129 common.red_gc = NULL;
130 #if GTK_CHECK_VERSION(2, 8, 0)
131 common.knob_surface = NULL;
132 common.insensitive_knob_surface = NULL;
133 common.shadow_pattern = NULL;
134 #endif
135 }
136
137
138 static void
gtk_knob_init(GtkKnob * knob)139 gtk_knob_init (GtkKnob *knob)
140 {
141 knob->adjustment = NULL;
142 knob->policy = GTK_UPDATE_CONTINUOUS;
143 knob->state = STATE_IDLE;
144 knob->center_x = 0;
145 knob->center_y = 0;
146 knob->saved_x = 0;
147 knob->saved_y = 0;
148 knob->old_value = 0.0;
149 knob->timer = 0;
150
151 common.refcount++;
152 }
153
154
155 GtkWidget*
gtk_knob_new(GtkAdjustment * adjustment)156 gtk_knob_new (GtkAdjustment *adjustment)
157 {
158 GtkKnob *knob = g_object_new (GTK_TYPE_KNOB, NULL);
159
160 gtk_knob_set_adjustment(knob, adjustment);
161
162 return GTK_WIDGET(knob);
163 }
164
165
166 static void
gtk_knob_finalize(GObject * object)167 gtk_knob_finalize (GObject *object)
168 {
169 /* GtkKnob *knob = GTK_KNOB (object); */
170
171 common.refcount--;
172 if (common.refcount == 0) gtk_knob_common_finalize();
173
174 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
175 }
176
177
178 static void
gtk_knob_destroy(GtkObject * object)179 gtk_knob_destroy (GtkObject *object)
180 {
181 GtkKnob *knob = GTK_KNOB(object);
182
183 if (knob->adjustment) {
184 g_signal_handlers_disconnect_by_func (knob->adjustment,
185 gtk_knob_adjustment_changed,
186 knob);
187 g_signal_handlers_disconnect_by_func (knob->adjustment,
188 gtk_knob_adjustment_value_changed,
189 knob);
190 g_object_unref(G_OBJECT(knob->adjustment));
191 knob->adjustment = NULL;
192 }
193 if (knob->timer) {
194 g_source_remove(knob->timer);
195 knob->timer = 0;
196 }
197
198 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
199 }
200
201
202 void
gtk_knob_set_fast_rendering(gboolean setting)203 gtk_knob_set_fast_rendering(gboolean setting)
204 {
205 #if GTK_CHECK_VERSION(2, 8, 0)
206 prefer_cairo = (setting ? FALSE : TRUE);
207 #else
208 prefer_cairo = FALSE;
209 #endif
210 }
211
212
213 GtkAdjustment*
gtk_knob_get_adjustment(GtkKnob * knob)214 gtk_knob_get_adjustment (GtkKnob *knob)
215 {
216 g_return_val_if_fail (GTK_IS_KNOB (knob), NULL);
217
218 if (!knob->adjustment)
219 gtk_knob_set_adjustment (knob, NULL);
220
221 return knob->adjustment;
222 }
223
224
225 void
gtk_knob_set_adjustment(GtkKnob * knob,GtkAdjustment * adjustment)226 gtk_knob_set_adjustment (GtkKnob *knob, GtkAdjustment *adjustment)
227 {
228 g_return_if_fail (GTK_IS_KNOB (knob));
229
230 if (!adjustment)
231 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
232 else
233 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
234
235 if (knob->adjustment) {
236 g_signal_handlers_disconnect_by_func (knob->adjustment,
237 gtk_knob_adjustment_changed,
238 knob);
239 g_signal_handlers_disconnect_by_func (knob->adjustment,
240 gtk_knob_adjustment_value_changed,
241 knob);
242 g_object_unref(G_OBJECT(knob->adjustment));
243 }
244
245 knob->adjustment = adjustment;
246 g_object_ref(G_OBJECT(knob->adjustment));
247 gtk_object_sink(GTK_OBJECT(knob->adjustment)); /* deprecated, but g_object_ref_sink() requires glib 2.10 or later */
248
249 g_signal_connect(G_OBJECT(adjustment), "changed",
250 G_CALLBACK(gtk_knob_adjustment_changed), (gpointer) knob);
251 g_signal_connect(G_OBJECT(adjustment), "value_changed",
252 G_CALLBACK(gtk_knob_adjustment_value_changed), (gpointer) knob);
253
254 gtk_knob_adjustment_changed (adjustment, knob);
255 }
256
257
258 void
gtk_knob_set_update_policy(GtkKnob * knob,GtkUpdateType policy)259 gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy)
260 {
261 g_return_if_fail (GTK_IS_KNOB (knob));
262
263 knob->policy = policy;
264 }
265
266
267 static void
gtk_knob_realize(GtkWidget * widget)268 gtk_knob_realize (GtkWidget *widget)
269 {
270 GtkKnob *knob;
271 GdkWindowAttr attributes;
272 gint attributes_mask;
273
274 g_return_if_fail (GTK_IS_KNOB (widget));
275
276 knob = GTK_KNOB (widget);
277 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
278
279 attributes.window_type = GDK_WINDOW_CHILD;
280 attributes.x = widget->allocation.x;
281 attributes.y = widget->allocation.y;
282 attributes.width = widget->allocation.width;
283 attributes.height = widget->allocation.height;
284 attributes.wclass = GDK_INPUT_OUTPUT;
285 attributes.visual = gtk_widget_get_visual (widget);
286 attributes.colormap = gtk_widget_get_colormap (widget);
287 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK |
288 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
289 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
290
291 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
292
293 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
294 gdk_window_set_user_data (widget->window, knob);
295
296 widget->style = gtk_style_attach (widget->style, widget->window);
297 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
298
299 gtk_knob_common_initialize(widget);
300 }
301
302
303 static void
gtk_knob_size_request(GtkWidget * widget,GtkRequisition * requisition)304 gtk_knob_size_request (GtkWidget *widget, GtkRequisition *requisition)
305 {
306 requisition->width = KNOB_SIZE;
307 requisition->height = KNOB_SIZE;
308 }
309
310
311 static void
gtk_knob_size_allocate(GtkWidget * widget,GtkAllocation * allocation)312 gtk_knob_size_allocate (GtkWidget *widget,
313 GtkAllocation *allocation)
314 {
315 g_return_if_fail (GTK_IS_KNOB (widget));
316 g_return_if_fail (allocation != NULL);
317
318 widget->allocation = *allocation;
319
320 if (GTK_WIDGET_REALIZED (widget)) {
321 gdk_window_move_resize (widget->window,
322 allocation->x, allocation->y,
323 allocation->width, allocation->height);
324 }
325 }
326
327
328 static gint
gtk_knob_button_press(GtkWidget * widget,GdkEventButton * event)329 gtk_knob_button_press (GtkWidget *widget, GdkEventButton *event)
330 {
331 GtkKnob *knob;
332
333 g_return_val_if_fail(GTK_IS_KNOB(widget), FALSE);
334 g_return_val_if_fail(event != NULL, FALSE);
335
336 knob = GTK_KNOB(widget);
337
338 switch (knob->state) {
339 case STATE_IDLE:
340 switch (event->button) {
341 case 1:
342 case 3:
343 gtk_grab_add(widget);
344 knob->state = STATE_PRESSED;
345 knob->center_x = widget->allocation.width / 2;
346 knob->center_y = widget->allocation.height / 2;
347 knob->saved_x = event->x;
348 knob->saved_y = event->y;
349 break;
350
351 default:
352 break;
353 }
354 break;
355
356 default:
357 break;
358 }
359
360 return FALSE;
361 }
362
363
364 static gint
gtk_knob_button_release(GtkWidget * widget,GdkEventButton * event)365 gtk_knob_button_release (GtkWidget *widget, GdkEventButton *event)
366 {
367 GtkKnob *knob;
368 gfloat value;
369
370 g_return_val_if_fail(GTK_IS_KNOB(widget), FALSE);
371 g_return_val_if_fail(event != NULL, FALSE);
372
373 knob = GTK_KNOB(widget);
374
375 switch (knob->state) {
376 case STATE_PRESSED:
377 gtk_grab_remove(widget);
378 knob->state = STATE_IDLE;
379
380 switch (event->button) {
381 case 1:
382 value = knob->adjustment->value - knob->adjustment->page_increment;
383 value = MAX(MIN(value, knob->adjustment->upper),
384 knob->adjustment->lower);
385 if (knob->adjustment->value != value) {
386 knob->adjustment->value = value;
387 g_signal_emit_by_name(G_OBJECT(knob->adjustment), "value_changed");
388 }
389 break;
390
391 case 3:
392 value = knob->adjustment->value + knob->adjustment->page_increment;
393 value = MAX(MIN(value, knob->adjustment->upper),
394 knob->adjustment->lower);
395 if (knob->adjustment->value != value) {
396 knob->adjustment->value = value;
397 g_signal_emit_by_name(G_OBJECT(knob->adjustment), "value_changed");
398 }
399 break;
400
401 default:
402 break;
403 }
404 break;
405
406 case STATE_DRAGGING:
407 gtk_grab_remove(widget);
408 knob->state = STATE_IDLE;
409
410 if (knob->policy != GTK_UPDATE_CONTINUOUS && knob->old_value != knob->adjustment->value)
411 g_signal_emit_by_name(G_OBJECT(knob->adjustment), "value_changed");
412
413 break;
414
415 default:
416 break;
417 }
418
419 return FALSE;
420 }
421
422
423 static gint
gtk_knob_motion_notify(GtkWidget * widget,GdkEventMotion * event)424 gtk_knob_motion_notify (GtkWidget *widget, GdkEventMotion *event)
425 {
426 GtkKnob *knob;
427 GdkModifierType mods;
428 gint x, y;
429
430 g_return_val_if_fail(GTK_IS_KNOB(widget), FALSE);
431 g_return_val_if_fail(event != NULL, FALSE);
432
433 knob = GTK_KNOB(widget);
434
435 x = event->x;
436 y = event->y;
437
438 if (event->is_hint || (event->window != widget->window))
439 gdk_window_get_pointer(widget->window, &x, &y, &mods);
440
441 switch (knob->state) {
442 case STATE_PRESSED:
443 knob->state = STATE_DRAGGING;
444 /* fall through */
445
446 case STATE_DRAGGING:
447 if (mods & GDK_BUTTON1_MASK) {
448 gtk_knob_update_mouse(knob, x, y, TRUE);
449 return TRUE;
450 } else if (mods & GDK_BUTTON3_MASK) {
451 gtk_knob_update_mouse(knob, x, y, FALSE);
452 return TRUE;
453 }
454 break;
455
456 default:
457 break;
458 }
459
460 return FALSE;
461 }
462
463
464 static gint
gtk_knob_timer_callback(GtkKnob * knob)465 gtk_knob_timer_callback (GtkKnob *knob)
466 {
467 g_return_val_if_fail(GTK_IS_KNOB(knob), FALSE);
468
469 if (knob->policy == GTK_UPDATE_DELAYED)
470 g_signal_emit_by_name(G_OBJECT(knob->adjustment), "value_changed");
471
472 return FALSE; /* don't keep running this timer */
473 }
474
475
476 static void
gtk_knob_update_mouse(GtkKnob * knob,gint x,gint y,gboolean absolute)477 gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean absolute)
478 {
479 gfloat old_value, new_value;
480 gdouble angle;
481 gint dv, dh;
482
483 g_return_if_fail(GTK_IS_KNOB(knob));
484
485 old_value = knob->adjustment->value;
486
487 if (absolute) {
488
489 angle = atan2(-y + knob->center_y, x - knob->center_x);
490 angle /= M_PI;
491 if (angle < -0.5)
492 angle += 2;
493
494 new_value = -(2.0/3.0) * (angle - 1.25); /* map [1.25pi, -0.25pi] onto [0, 1] */
495 new_value *= knob->adjustment->upper - knob->adjustment->lower;
496 new_value += knob->adjustment->lower;
497
498 } else {
499
500 dv = knob->center_y - y; /* inverted cartesian graphics coordinate system */
501 dh = x - knob->center_x;
502
503 if (abs(dv) < HALF_KNOB_SIZE && abs(dh) < HALF_KNOB_SIZE) {
504
505 /* translate close-in motion into fine adjustment */
506 dv = knob->saved_y - y;
507 dh = x - knob->saved_x;
508 new_value = knob->adjustment->value +
509 (float)(dv + dh) * knob->adjustment->step_increment;
510
511 } else if (abs(dv) > abs(dh)) {
512
513 /* translate up-and-down motion into fine adjustment */
514 dv = knob->saved_y - y;
515 new_value = knob->adjustment->value +
516 (float)dv * knob->adjustment->step_increment;
517
518 } else {
519
520 /* translate side-to-side motion into coarse adjustment */
521 dh = x - knob->saved_x;
522 new_value = knob->adjustment->value +
523 (float)dh * (knob->adjustment->upper -
524 knob->adjustment->lower) / 300.0f;
525
526 }
527 knob->saved_x = x;
528 knob->saved_y = y;
529 }
530
531 new_value = MAX(MIN(new_value, knob->adjustment->upper),
532 knob->adjustment->lower);
533
534 knob->adjustment->value = new_value;
535
536 if (knob->adjustment->value != old_value) {
537
538 if (knob->policy == GTK_UPDATE_CONTINUOUS)
539 g_signal_emit_by_name(G_OBJECT(knob->adjustment), "value_changed");
540 else {
541 gtk_widget_queue_draw (GTK_WIDGET(knob));
542
543 if (knob->policy == GTK_UPDATE_DELAYED) {
544 if (knob->timer)
545 g_source_remove(knob->timer);
546
547 knob->timer = g_timeout_add (UPDATE_DELAY_LENGTH,
548 (GSourceFunc) gtk_knob_timer_callback,
549 (gpointer) knob);
550 }
551 }
552 }
553 }
554
555
556 static void
gtk_knob_adjustment_changed(GtkAdjustment * adjustment,gpointer data)557 gtk_knob_adjustment_changed(GtkAdjustment *adjustment, gpointer data)
558 {
559 GtkKnob *knob;
560
561 g_return_if_fail(adjustment != NULL);
562 g_return_if_fail(data != NULL);
563
564 knob = GTK_KNOB(data);
565
566 knob->old_value = adjustment->value;
567
568 gtk_widget_queue_draw (GTK_WIDGET(knob));
569 }
570
571 static void
gtk_knob_adjustment_value_changed(GtkAdjustment * adjustment,gpointer data)572 gtk_knob_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data)
573 {
574 GtkKnob *knob;
575
576 g_return_if_fail(adjustment != NULL);
577 g_return_if_fail(data != NULL);
578
579 knob = GTK_KNOB(data);
580
581 if (knob->old_value != adjustment->value) {
582 knob->old_value = adjustment->value;
583
584 gtk_widget_queue_draw (GTK_WIDGET(knob));
585 }
586 }
587
588
589 static void
gtk_knob_paint_xlib(GtkWidget * widget,int center_x,int center_y)590 gtk_knob_paint_xlib(GtkWidget *widget, int center_x, int center_y)
591 {
592 GtkKnob *knob = GTK_KNOB(widget);
593 gfloat dx, dy;
594
595 gdk_window_clear_area(widget->window, 0, 0, widget->allocation.width, widget->allocation.height);
596
597 center_x -= HALF_KNOB_SIZE;
598 center_y -= HALF_KNOB_SIZE;
599 gdk_gc_set_clip_origin(common.mask_gc, center_x, center_y);
600
601 dx = knob->adjustment->value - knob->adjustment->lower;
602 dy = knob->adjustment->upper - knob->adjustment->lower;
603
604 if (dy != 0 && GTK_WIDGET_IS_SENSITIVE (widget)) {
605 dx = MIN(MAX(dx / dy, 0), 1);
606 dx = -1.5 * dx + 1.25;
607
608 gdk_draw_arc (widget->window, common.red_gc, TRUE,
609 1 + center_x , 1 + center_y,
610 KNOB_SIZE - 4, KNOB_SIZE - 2,
611 dx * 180.f * 64.f, (1.25f - dx) * 180.f * 64.f);
612 gdk_draw_pixmap(widget->window, common.mask_gc, common.pixmap,
613 0, 0, center_x, center_y, KNOB_SIZE, KNOB_SIZE);
614
615 dx *= M_PI;
616 dy = -sin(dx) * 11 + 15.5;
617 dx = cos(dx) * 11 + 15.5;
618
619 gdk_draw_line(widget->window, widget->style->white_gc,
620 15 + center_x, 16 + center_y,
621 dx + center_x, dy + center_y);
622 } else {
623 gdk_draw_pixmap(widget->window, common.mask_gc, common.insensitive_pixmap,
624 0, 0, center_x, center_y, KNOB_SIZE, KNOB_SIZE);
625 }
626 }
627
628
629 #if GTK_CHECK_VERSION(2, 8, 0)
630 static void
gtk_knob_paint_cairo(GtkWidget * widget,cairo_t * cr)631 gtk_knob_paint_cairo(GtkWidget *widget, cairo_t *cr)
632 {
633 GtkKnob *knob = GTK_KNOB(widget);
634 gfloat value, range;
635
636 if (GTK_WIDGET_IS_SENSITIVE (widget)) {
637
638 range = knob->adjustment->upper - knob->adjustment->lower;
639 if (fabs(range) < 1e-37) {
640 value = 0.0;
641 } else {
642 value = MAX(MIN(knob->adjustment->value, knob->adjustment->upper),
643 knob->adjustment->lower);
644 value = value - knob->adjustment->lower;
645 value /= range; /* now scaled 0.0 to 1.0 */
646 }
647
648 /* draw the red arc */
649 cairo_set_source_rgb (cr, 1.0, 0, 0);
650 cairo_move_to (cr, HALF_KNOB_SIZE, HALF_KNOB_SIZE);
651 cairo_arc (cr, HALF_KNOB_SIZE, HALF_KNOB_SIZE, (KNOB_SIZE * 0.47),
652 M_PI * 0.75, M_PI * 0.75 + value * (1.5 * M_PI));
653 cairo_close_path (cr);
654 cairo_fill (cr);
655
656 /* draw the knob shadow */
657 cairo_set_source (cr, common.shadow_pattern);
658 cairo_paint (cr);
659
660 /* paint the knob and reference points over what we have so far */
661 cairo_set_source_surface (cr, common.knob_surface, 0, 0);
662 cairo_paint (cr);
663
664 /* add cursor to knob */
665 cairo_translate (cr, HALF_KNOB_SIZE, HALF_KNOB_SIZE);
666 cairo_rotate (cr, M_PI * 0.75 + value * (1.5 * M_PI));
667 cairo_set_line_width (cr, KNOB_SIZE / 32.0 * 1.5);
668 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
669 cairo_move_to (cr, KNOB_SIZE * 0.06, 0);
670 cairo_line_to (cr, KNOB_SIZE * 0.30, 0);
671 cairo_stroke (cr);
672
673 } else { /* insensitive */
674 cairo_set_source_surface (cr, common.insensitive_knob_surface, 0, 0);
675 cairo_paint (cr);
676 }
677 }
678 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
679
680
681 static gboolean
gtk_knob_expose(GtkWidget * widget,GdkEventExpose * event)682 gtk_knob_expose (GtkWidget *widget, GdkEventExpose *event)
683 {
684 int center_x, center_y;
685 #if GTK_CHECK_VERSION(2, 8, 0)
686 int l, t, r, b;
687 cairo_t *cr;
688 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
689
690 g_return_val_if_fail(GTK_IS_KNOB(widget), FALSE);
691 g_return_val_if_fail(event != NULL, FALSE);
692
693 /* minimize the clip area to just what we'll actually draw (32x32 at most) */
694 center_x = widget->allocation.width / 2;
695 center_y = widget->allocation.height / 2;
696
697 if (prefer_cairo) {
698 #if GTK_CHECK_VERSION(2, 8, 0)
699 if (common.knob_surface == NULL)
700 gtk_knob_common_initialize(widget);
701
702 if ((center_x - HALF_KNOB_SIZE >= event->area.x + event->area.width) ||
703 (center_x + HALF_KNOB_SIZE <= event->area.x) ||
704 (center_y - HALF_KNOB_SIZE >= event->area.y + event->area.height) ||
705 (center_y + HALF_KNOB_SIZE <= event->area.y)) {
706 /* clip area is empty */
707 return FALSE;
708 }
709 l = MAX(event->area.x, center_x - HALF_KNOB_SIZE);
710 r = MIN(event->area.x + event->area.width, center_x + HALF_KNOB_SIZE);
711 t = MAX(event->area.y, center_y - HALF_KNOB_SIZE);
712 b = MIN(event->area.y + event->area.height, center_y + HALF_KNOB_SIZE);
713 cr = gdk_cairo_create (widget->window);
714 cairo_rectangle (cr, l, t, r - l, b - t);
715 cairo_clip (cr);
716 cairo_translate(cr, center_x - HALF_KNOB_SIZE, center_y - HALF_KNOB_SIZE);
717
718 gtk_knob_paint_cairo(widget, cr);
719
720 cairo_destroy (cr);
721 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
722 } else {
723 if (common.pixmap == NULL)
724 gtk_knob_common_initialize(widget);
725
726 gtk_knob_paint_xlib(widget, center_x, center_y);
727 }
728
729 return FALSE;
730 }
731
732
733 /* forward declarations of XPM data below */
734 static char * knob_xpm[];
735 static char * insensitive_knob_xpm[];
736
737 static void
gtk_knob_common_initialize_xlib(GtkWidget * widget)738 gtk_knob_common_initialize_xlib(GtkWidget *widget)
739 {
740 GdkColor color = { 0, 0xffff, 0, 0 };
741
742 common.pixmap = gdk_pixmap_create_from_xpm_d(widget->window, &common.mask,
743 &widget->style->bg[GTK_STATE_NORMAL],
744 knob_xpm);
745 common.insensitive_pixmap = gdk_pixmap_create_from_xpm_d(widget->window, &common.mask,
746 &widget->style->bg[GTK_STATE_NORMAL],
747 insensitive_knob_xpm);
748
749 common.mask_gc = gdk_gc_new(widget->window);
750 gdk_gc_copy(common.mask_gc, widget->style->bg_gc[GTK_STATE_NORMAL]);
751 gdk_gc_set_clip_mask(common.mask_gc, common.mask);
752
753 common.red_gc = gdk_gc_new(widget->window);
754 gdk_gc_copy(common.red_gc, widget->style->bg_gc[GTK_STATE_NORMAL]);
755 gdk_colormap_alloc_color(gtk_widget_get_colormap (widget), &color, FALSE, TRUE);
756 gdk_gc_set_foreground(common.red_gc, &color);
757 }
758
759 static void
gtk_knob_common_finalize_xlib(void)760 gtk_knob_common_finalize_xlib(void)
761 {
762 if (common.pixmap) {
763 gdk_pixmap_unref(common.pixmap);
764 common.pixmap = NULL;
765 }
766 if (common.insensitive_pixmap) {
767 gdk_pixmap_unref(common.insensitive_pixmap);
768 common.insensitive_pixmap = NULL;
769 }
770 if (common.mask) {
771 gdk_bitmap_unref(common.mask);
772 common.mask = NULL;
773 }
774 if (common.mask_gc) {
775 gdk_gc_unref(common.mask_gc);
776 common.mask_gc = NULL;
777 }
778 if (common.red_gc) {
779 gdk_gc_unref(common.red_gc);
780 common.red_gc = NULL;
781 }
782 }
783
784 #if GTK_CHECK_VERSION(2, 8, 0)
785
786 /* forward declarations of PNG data below */
787 static size_t knob_c_png_length;
788 static unsigned char knob_c_png[];
789 static size_t knob_i_png_length;
790 static unsigned char knob_i_png[];
791
792 struct cairo_read_func_closure {
793 size_t length;
794 size_t offset;
795 unsigned char *data;
796 };
797
798 static cairo_status_t
cairo_read_func(void * closure,unsigned char * data,unsigned int length)799 cairo_read_func(void *closure, unsigned char *data, unsigned int length)
800 {
801 struct cairo_read_func_closure *cl = (struct cairo_read_func_closure *)closure;
802 size_t l = MIN(length, cl->length - cl->offset);
803
804 memcpy(data, cl->data + cl->offset, l);
805
806 cl->offset += l;
807
808 return CAIRO_STATUS_SUCCESS;
809 }
810
811 static void
gtk_knob_common_initialize_cairo(void)812 gtk_knob_common_initialize_cairo(void)
813 {
814 struct cairo_read_func_closure cl;
815 cairo_pattern_t *pat;
816
817 /* create knob surfaces */
818 cl.length = knob_c_png_length;
819 cl.offset = 0;
820 cl.data = knob_c_png;
821 common.knob_surface = cairo_image_surface_create_from_png_stream(cairo_read_func, &cl);
822 cl.length = knob_i_png_length;
823 cl.offset = 0;
824 cl.data = knob_i_png;
825 common.insensitive_knob_surface = cairo_image_surface_create_from_png_stream(cairo_read_func, &cl);
826
827 /* create the shadow pattern */
828 pat = cairo_pattern_create_radial (KNOB_SIZE * 0.61, KNOB_SIZE * 0.61, 0.0,
829 KNOB_SIZE * 0.61, KNOB_SIZE * 0.61, KNOB_SIZE * 0.4); /* 0.375 */
830 cairo_pattern_add_color_stop_rgba (pat, 0.75, 0, 0, 0, 0.5);
831 cairo_pattern_add_color_stop_rgba (pat, 0.90, 0, 0, 0, 0.1);
832 cairo_pattern_add_color_stop_rgba (pat, 1.00, 0, 0, 0, 0);
833 common.shadow_pattern = pat;
834 }
835
836 static void
gtk_knob_common_finalize_cairo(void)837 gtk_knob_common_finalize_cairo(void)
838 {
839 if (common.knob_surface) {
840 cairo_surface_destroy (common.knob_surface);
841 common.knob_surface = NULL;
842 }
843 if (common.insensitive_knob_surface) {
844 cairo_surface_destroy (common.insensitive_knob_surface);
845 common.insensitive_knob_surface = NULL;
846 }
847 if (common.shadow_pattern) {
848 cairo_pattern_destroy (common.shadow_pattern);
849 common.shadow_pattern = NULL;
850 }
851 }
852
853 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
854
855
856 static void
gtk_knob_common_initialize(GtkWidget * widget)857 gtk_knob_common_initialize(GtkWidget *widget)
858 {
859 #if GTK_CHECK_VERSION(2, 8, 0)
860 if (prefer_cairo) {
861 gtk_knob_common_initialize_cairo();
862 gtk_knob_common_finalize_xlib();
863 } else {
864 gtk_knob_common_initialize_xlib(widget);
865 gtk_knob_common_finalize_cairo();
866 }
867 #else /* GTK_CHECK_VERSION(2, 8, 0) */
868 gtk_knob_common_initialize_xlib(widget);
869 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
870 }
871
872 static void
gtk_knob_common_finalize(void)873 gtk_knob_common_finalize(void)
874 {
875 gtk_knob_common_finalize_xlib();
876 #if GTK_CHECK_VERSION(2, 8, 0)
877 gtk_knob_common_finalize_cairo();
878 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
879 }
880
881
882 static char * knob_xpm[] = {
883 "32 32 106 2",
884 " c None",
885 ". c #FCFCFD",
886 "+ c #0A0A20",
887 "@ c #6B6B9E",
888 "# c #8989B3",
889 "$ c #66669A",
890 "% c #AEAECC",
891 "& c #AAAACA",
892 "* c #A6A6C7",
893 "= c #9C9CC0",
894 "- c #9494BB",
895 "; c #8E8EB7",
896 "> c #8C8CB6",
897 ", c #7F7FAD",
898 "' c #A0A0C3",
899 ") c #B5B5D1",
900 "! c #B0B0CE",
901 "~ c #8181AE",
902 "{ c #7C7CAA",
903 "] c #7575A5",
904 "^ c #595991",
905 "/ c #9696BC",
906 "( c #8383AF",
907 "_ c #7A7AA9",
908 ": c #7171A3",
909 "< c #7070A2",
910 "[ c #626298",
911 "} c #42427E",
912 "| c #9292BA",
913 "1 c #6E6EA0",
914 "2 c #616197",
915 "3 c #5F5F95",
916 "4 c #585890",
917 "5 c #464682",
918 "6 c #2E2E6D",
919 "7 c #9A9ABF",
920 "8 c #69699D",
921 "9 c #5B5B92",
922 "0 c #4C4C86",
923 "a c #363674",
924 "b c #222262",
925 "c c #5E5E94",
926 "d c #52528B",
927 "e c #3F3F7C",
928 "f c #282868",
929 "g c #A2A2C4",
930 "h c #43437F",
931 "i c #2D2D6C",
932 "j c #1F1F5E",
933 "k c #333371",
934 "l c #202060",
935 "m c #30306F",
936 "n c #1D1D58",
937 "o c #53538C",
938 "p c #454581",
939 "q c #1C1C54",
940 "r c #19194C",
941 "s c #50508A",
942 "t c #3B3B79",
943 "u c #232363",
944 "v c #181848",
945 "w c #15153F",
946 "x c #4A4A85",
947 "y c #353573",
948 "z c #1C1C56",
949 "A c #14143E",
950 "B c #121237",
951 "C c #2F2F6E",
952 "D c #121236",
953 "E c #7777A7",
954 "F c #292969",
955 "G c #161642",
956 "H c #0E0E2C",
957 "I c #13133A",
958 "J c #0C0C26",
959 "K c #393977",
960 "L c #0E0E2B",
961 "M c #4F4F89",
962 "N c #161644",
963 "O c #0A0A1F",
964 "P c #474783",
965 "Q c #41417D",
966 "R c #3E3E7B",
967 "S c #54548D",
968 "T c #171747",
969 "U c #0A0A1E",
970 "V c #080819",
971 "W c #1E1E5A",
972 "X c #0F0F2D",
973 "Y c #09091C",
974 "Z c #070717",
975 "` c #2B2B6A",
976 " . c #343472",
977 ".. c #252565",
978 "+. c #19194B",
979 "@. c #0D0D29",
980 "#. c #070715",
981 "$. c #1A1A4F",
982 "%. c #101032",
983 "&. c #0D0D28",
984 "*. c #0F0F2F",
985 "=. c #101030",
986 "-. c #0B0B22",
987 ";. c #09091B",
988 ">. c #060614",
989 ",. c #060612",
990 " ",
991 " + + ",
992 " + + ",
993 " ",
994 " @ # # $ ",
995 " % & * = - ; > # # , ",
996 " ' ) ! & = ; # ~ , { { ] @ ^ ",
997 " % ) ) * / ( _ : < @ @ @ @ [ ^ } ",
998 " & ) ) * | { 1 $ 2 2 3 3 3 3 3 4 5 6 ",
999 " 7 ) ) & | _ 8 3 3 3 3 3 3 3 3 3 9 0 a b ",
1000 " & % * | { $ 3 3 3 3 3 3 3 3 3 3 c d e f ",
1001 " ' & g | { $ 3 3 3 3 3 3 3 3 3 3 3 3 4 h i j ",
1002 " * * / , @ 3 3 3 3 3 3 3 3 3 3 3 3 3 9 0 k l ",
1003 " g ' > ] 2 3 3 3 3 3 3 3 3 3 3 3 3 3 ^ 0 m n ",
1004 " 1 ' = ( 1 3 3 3 3 3 3 3 3 3 3 3 3 3 9 o p i q r ",
1005 " > = / , @ 3 3 3 3 3 3 3 3 3 3 3 3 c ^ s t u v w ",
1006 " # 7 ; { $ 3 3 3 3 3 3 3 3 3 3 3 3 9 4 x y z A B ",
1007 " 3 > ( ] 2 3 3 3 3 3 3 3 3 3 3 3 3 ^ d 5 C r D B ",
1008 " E E @ 3 3 3 3 3 3 3 3 3 3 3 3 9 4 s e F G H ",
1009 " [ [ 3 c c 3 3 3 3 3 3 3 3 3 3 9 d 5 a j I J ",
1010 " c ^ o o 9 9 3 3 3 3 c 9 9 9 ^ d 5 K u G L + ",
1011 " s x x s 4 9 3 3 c 9 4 o s M x a u N H O ",
1012 " P Q R h M S 9 9 ^ o M P h e k b T L U V ",
1013 " K k a t h 0 M 0 x h K m f W G X Y Z ",
1014 " ` i ` i 6 k .m ` ..n +.B @.Y #. ",
1015 " + + l q r +.v $.$.v w %.&.U Z #. + + ",
1016 " + + B *.=.=.=.@.-.;.>.,. + + ",
1017 " %.J O J ",
1018 " ",
1019 " ",
1020 " ",
1021 " "};
1022
1023 static char * insensitive_knob_xpm[] = {
1024 "32 32 82 1",
1025 " c None",
1026 ". c #777777",
1027 "+ c #B8B8B8",
1028 "@ c #C7C7C7",
1029 "# c #B5B5B5",
1030 "$ c #D9D9D9",
1031 "% c #D7D7D7",
1032 "& c #D5D5D5",
1033 "* c #D0D0D0",
1034 "= c #CCCCCC",
1035 "- c #CACACA",
1036 "; c #C8C8C8",
1037 "> c #C2C2C2",
1038 ", c #D2D2D2",
1039 "' c #DCDCDC",
1040 ") c #DADADA",
1041 "! c #C3C3C3",
1042 "~ c #C0C0C0",
1043 "{ c #BDBDBD",
1044 "] c #AFAFAF",
1045 "^ c #CDCDCD",
1046 "/ c #C4C4C4",
1047 "( c #BBBBBB",
1048 "_ c #BABABA",
1049 ": c #B3B3B3",
1050 "< c #A3A3A3",
1051 "[ c #CBCBCB",
1052 "} c #B9B9B9",
1053 "| c #B2B2B2",
1054 "1 c #AEAEAE",
1055 "2 c #A5A5A5",
1056 "3 c #989898",
1057 "4 c #CFCFCF",
1058 "5 c #B7B7B7",
1059 "6 c #B0B0B0",
1060 "7 c #A8A8A8",
1061 "8 c #9C9C9C",
1062 "9 c #919191",
1063 "0 c #B1B1B1",
1064 "a c #ABABAB",
1065 "b c #A1A1A1",
1066 "c c #959595",
1067 "d c #D3D3D3",
1068 "e c #8F8F8F",
1069 "f c #9A9A9A",
1070 "g c #909090",
1071 "h c #999999",
1072 "i c #8D8D8D",
1073 "j c #ACACAC",
1074 "k c #A4A4A4",
1075 "l c #8B8B8B",
1076 "m c #888888",
1077 "n c #AAAAAA",
1078 "o c #9F9F9F",
1079 "p c #929292",
1080 "q c #878787",
1081 "r c #838383",
1082 "s c #A7A7A7",
1083 "t c #8C8C8C",
1084 "u c #808080",
1085 "v c #BEBEBE",
1086 "w c #848484",
1087 "x c #7C7C7C",
1088 "y c #818181",
1089 "z c #797979",
1090 "A c #9E9E9E",
1091 "B c #858585",
1092 "C c #A2A2A2",
1093 "D c #868686",
1094 "E c #767676",
1095 "F c #757575",
1096 "G c #8E8E8E",
1097 "H c #737373",
1098 "I c #969696",
1099 "J c #9B9B9B",
1100 "K c #939393",
1101 "L c #7A7A7A",
1102 "M c #8A8A8A",
1103 "N c #7E7E7E",
1104 "O c #7D7D7D",
1105 "P c #787878",
1106 "Q c #727272",
1107 " ",
1108 " .. ",
1109 " .. ",
1110 " ",
1111 " +@@# ",
1112 " $%&*=-;@@> ",
1113 " ,')%*-@!>~~{+] ",
1114 " $''&^/~(_++++:]< ",
1115 " %''&[~}#::|||||123 ",
1116 " 4''%[~5|||||||||6789 ",
1117 " %$&[~#||||||||||0abc ",
1118 " ,%d[~#||||||||||||1<3e ",
1119 " &&^>+|||||||||||||67fg ",
1120 " d,;{:|||||||||||||]7hi ",
1121 " },*/}|||||||||||||6jk3lm ",
1122 " ;*^>+||||||||||||0]nopqr ",
1123 " @4-~#||||||||||||61s8tru ",
1124 " |;/{:||||||||||||]a2hmuu ",
1125 " vv+||||||||||||61nbcwx ",
1126 " ::|00||||||||||6a28eyz ",
1127 " 0]jj66||||0666]a2Apwx. ",
1128 " nssn16||061jnns8pBx. ",
1129 " 2Cb<nj66]jn2<bf9DxEF ",
1130 " Af8o<7n7s<AhcGwxEH ",
1131 " I3I33fJhIKimuLEH ",
1132 " .. glmmqMMqrNLEHH .. ",
1133 " .. uOOOOLPFQQ .. ",
1134 " Nz.z ",
1135 " ",
1136 " ",
1137 " ",
1138 " "};
1139
1140 #if GTK_CHECK_VERSION(2, 8, 0)
1141
1142 static size_t knob_c_png_length = 1082;
1143 static unsigned char knob_c_png[1082] =
1144 "\211PNG\15\12\32\12\0\0\0\15IHDR\0\0\0\40\0\0\0\40\10\6\0\0\0szz\364"
1145 "\0\0\0\1sRGB\0\256\316\34\351\0\0\0\6bKGD\0\377\0\377\0\377\240\275\247"
1146 "\223\0\0\3\342IDATX\303\355VM\213\34U\24=\357\325Gw'0\321\4\304\30w\371"
1147 "\15a\\d\231a6\1]E\30W\16\10.t'\"nD\307\215\333\254$\213\350&\270\226"
1148 "\20\2\223E>6\306e\230\14\202\211`23NwM\367t}\276z_\367=\27\325\335d\222"
1149 "\350twt!\346@AQE\335{\352\336s\356}\300\177\34~t\315\15\216\377;\330"
1150 "<\37\335\272\365\313\345$\311\227\262L\236\320\332\40\216\303\301\261"
1151 "c\235\33\27.,\256\376k\4n\336|\360q\232\346\27\215!XK\20BAJ\3\255-\234"
1152 "\363\40\"\0@U)xO\77\257\255\275\373\326\77F`}\375\2760\206:\306\20\264"
1153 "\266\310s\201<\257a\214\205\224\346\0\1\245\14\352ZCk[\\\272\364\301"
1154 "\302\13\23\270v\355\336D\345Y&\220\246\25\6\203\2u\255Q\327\32\336{\30"
1155 "c\17|#\245\206\326\2044-p\365\352gln\2O'\357\367\13$I\212<\27\220R\303"
1156 "\230\346\257\235s\7\2032\6\"\207\252R\350\367S\334\271\263\306f\266\341"
1157 "\372\372}1\276o\2\25\350v\207\30\14\12dY\5\245\14\234s\317$\37#\14\3"
1158 "\264Z\21:\235\26\226\227\277\334\236\211\300\355\333\17>MS\321Q\312\40"
1159 "\313\4\272\335\24I\222\242\337\317\40\204\234J\264A\20\240\325\212q\344"
1160 "H\7E\241N\235\77\377\325\367S\23\330\331\31|\3\0e)'eO\222\24J\231\351"
1161 "\355\305\200(\12\21\206\1\242(D\257\227\255\314\320\2\17k\11e)1\30\24"
1162 "\30\16\313\231\222\3\36\336{p\316\320\351\304\210\343\10D>\232\212\300"
1163 "\365\353\33\227\255m\354&\204\206\20\22B\250\331\26\204\307\310\232\16"
1164 "\336\3D\4\"\211s\347>\371\361\31\255<\375\240(\304\222sM\5\352ZM\304"
1165 "6+\32\201\2J\351\21\21\13k\353\327\16%\40\245=1\256\200\265\16Dn\276"
1166 "\31\3170\262\242\204\20""5\254-\261\277\257\337<\224@\303\336CJ\3\"z"
1167 "f\310\314\322\6\"\202R\32J\25""0\246\6c\366p\15(e\6y^\243\252$\2242\223"
1168 "a3\17\234s\320\332\200H\200H\0""0\371\241\4\30\303\215\275\275\14e\331"
1169 "\210o\236\3763\326LCk\233\12Z[\203\250F\247\23<\234j\24\257\256~\353"
1170 "\1L\26\3148\250\367\323$g\340\234\3039\217~\77\303\366\366.\312\3627"
1171 "(\325\307\326\326]6\225\6\232\3367k\227s\216v;\236\370\332\373\306\343"
1172 "\1779Z9\7c\14E!\220$\373\250\353\77`L\6\316\235\231z\20\2359s\372\243"
1173 "q\377\211\34\254u\10\202\0\214q\4A\0\316\331s\313>~\227\246%vv\22d\331"
1174 "\357\220\262\7kK,,DWf\332\206++\27\207E!^a\214#\212B\34=\332A\20p\204"
1175 "!\7\21M*\301\30\3cM(k\35\322\264D\2577@\226m\241\256\267`m\2010\364\335"
1176 "G\217\356\235\234y\35//\177\355\211\10a\30\"\212\"\264Z\21\332\355h\264"
1177 "n\351\200\320\2242\250*\211<\37\242\252v\241T\2\255\207pNc8\34\276\241"
1178 "Tow\256\3\311\331\263\237\373\40\10\340\234\7\347M\307\342\270\221N\223"
1179 "\2749\226)U\302\332\22R\356\301\230\34\326\26pN\242\333\375u\256\3\211"
1180 "\177\362\375\322\322\27\333\275\336\356)\"9\32""2\26\234\267F^W\260\266"
1181 "\2061\305\304\357D\22q\34\364\36\77\336|\375y\361f&\320T\342\303\357"
1182 "\372\375\235\367\244,#\306\330\23\216Qp\256\271\210$\30200\307\217\277"
1183 "zec\343\247\367\377.\336\13\35\313\27\27\337\371\241,\325i!\206'\235"
1184 "S\10C\226\267\333\361\303\315\315\273o\343%^bF\374\11\251\215\305RV\321"
1185 "\250V\0\0\0\0IEND\256B`\202";
1186
1187 static size_t knob_i_png_length = 819;
1188 static unsigned char knob_i_png[819] =
1189 "\211PNG\15\12\32\12\0\0\0\15IHDR\0\0\0\40\0\0\0\40\10\6\0\0\0szz\364"
1190 "\0\0\0\1sRGB\0\256\316\34\351\0\0\2\355IDATX\303\355W\273N#A\20\254\331"
1191 "]\303O8#'u@d\211\4\221\372\3\10\220\34\20\\\200D\300\27\40K\266d\210"
1192 "\20\374\7!1\21\22\"[9\363\37\354kf\272{\346\22\317j\15\346\3305Gp:Zr"
1193 "fOWUwW\267\201\1779\306\343\361\343x<~\374\312\33\21\376\367P\333\374"
1194 "\350\365\365\365\210\210\6\314\334\27\21""8\347\226\336\373\247\203\203"
1195 "\203\207o\3\220\246\351>3O\234s\273\336{Xk!\"X\1\200\367\36\0@D\246("
1196 "\212\213\343\343\343\227\277\6\40M\323{\0{!\2411\246\6\300\314\360\336"
1197 "\3039\7\0\20\21\20\21\312\262\\\214F\243\323/\3H\323\264\356rc\14\252"
1198 "\252BUU`f\20\321Z\362\20D\4\"B\236\347899\31n\15\340m\362\242(P\24\5"
1199 "\2141`f\210\10\0\324\3627CDP\226%\262,\303\331\331\331\260\363\30\256"
1200 "d\7\0Xk\353\344UUAk]K\277)9\0(\245\20\3071\222$\301l6\273\357\4\40M\323"
1201 "}k\355\36""3\303\30\203<\317k\0\326\332v\6\23EH\222\4;;;\210\343xo6\233"
1202 "\355\267\6\240\265\236\274e^\24\5\230\271\323\210\305q\\+\341\234\233"
1203 "\264\6\240\224\252G\255)y\347\31W\12\275^/\0\331m\5\340\371\371\371("
1204 "\214[\350\346\266\262\277\215\320\37\336{\210\10&\223\311Q\33\5\6\241"
1205 "\213\231\271n\266\256\341\234[3*\347\34\210h\360\366{\311\6\324\375M"
1206 "\16\267\15{\347\34\254\265\260\326\202\210\40\"\375O\1""4\3478\260\330"
1207 "\206}xCD`\255\5""3\2773\254\215%\320Z/\265\326k^\277\15\373&\201\306"
1208 ";\313O\1\224e\371T\226e-[\327\22\4\226!y\350\243\225u\77}\12\340\360"
1209 "\360\360\241i\271\333D\230\240P\377\240\300\325\325\325C\253\36p\316"
1210 "\31\21\331\15\362'IR\273\333G\214\233\322\33c\326v\207\265\26\3169\323"
1211 "\332\210D\344\"x@`\262i\353\205)a\346\272dD\204\252\252\220e\31\262,"
1212 "CUU\40\"\0\270h\15`4\32\2750\363\"$7\306\2041\252g:\324\267\371\35\255"
1213 "5\262,[[\\+\366\213\351t\372\322y\35\337\335\335=23\242(\2527[\257\327"
1214 "C\24Ek\354\233j5o\206P\377\371|>\334\372\40\271\271\271yTJ\301{\17\245"
1215 "\24\224R\210\242\10J\251\2651\13\15\27\256\245\240\330\237\222\177\10"
1216 "\40\334\372\267\267\267C\0\230N\247\367D\264'\"\365\15\20\307\361;\263"
1217 "\11\335\277j\336\305|>\77\335\364^\347\377\5\347\347\347\247\0~i\255"
1218 "M\250m\236\347k\237\306\251f\242(\372\25\222\177\313Y~yyy\244\224\32"
1219 "Xk\373\253%\263\4\360t}}\375\200\237\370\211\216\361\33\353\274\40}\314"
1220 "\227E/\0\0\0\0IEND\256B`\202";
1221
1222 #endif /* GTK_CHECK_VERSION(2, 8, 0) */
1223
1224