025bb16ea69719fa974934627f975c2bfe9abe04
[ardour.git] / gtk2_ardour / cairo_widget.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program 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 program 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     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "cairo_widget.h"
21 #include "gui_thread.h"
22
23 CairoWidget::CairoWidget ()
24         : _width (1)
25         , _height (1)
26         , _active_state (CairoWidget::ActiveState (0))
27         , _visual_state (CairoWidget::VisualState (0))
28         , _dirty (true)
29         , _pixmap (0)
30           
31 {
32
33 }
34
35 CairoWidget::~CairoWidget ()
36 {
37         if (_pixmap) {
38                 g_object_unref (_pixmap);
39         }
40 }
41
42 bool
43 CairoWidget::on_expose_event (GdkEventExpose *event)
44 {
45         Gdk::Rectangle const exposure (
46                 event->area.x, event->area.y, event->area.width, event->area.height
47                 );
48
49         Gdk::Rectangle r = exposure;
50         Gdk::Rectangle content (0, 0, _width, _height);
51         bool intersects;
52         r.intersect (content, intersects);
53
54         if (intersects) {
55
56                 GdkDrawable* drawable = get_window()->gobj ();
57
58                 if (_dirty) {
59
60                         if (_pixmap) {
61                                 g_object_unref (_pixmap);
62                         }
63
64                         _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
65
66                         cairo_t* cr = gdk_cairo_create (_pixmap);
67                         render (cr);
68                         cairo_destroy (cr);
69
70                         _dirty = false;
71                 }
72
73                 gdk_draw_drawable (
74                         drawable,
75                         get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
76                         _pixmap,
77                         r.get_x(),
78                         r.get_y(),
79                         r.get_x(),
80                         r.get_y(),
81                         r.get_width(),
82                         r.get_height()
83                         );
84         }
85
86         return true;
87 }
88
89 /** Marks the widget as dirty, so that render () will be called on
90  *  the next GTK expose event.
91  */
92
93 void
94 CairoWidget::set_dirty ()
95 {
96         ENSURE_GUI_THREAD (*this, &CairoWidget::set_dirty)
97
98         _dirty = true;
99         queue_draw ();
100 }
101
102 /** Handle a size allocation.
103  *  @param alloc GTK allocation.
104  */
105 void
106 CairoWidget::on_size_allocate (Gtk::Allocation& alloc)
107 {
108         Gtk::EventBox::on_size_allocate (alloc);
109
110         _width = alloc.get_width ();
111         _height = alloc.get_height ();
112
113         set_dirty ();
114 }
115
116 Gdk::Color
117 CairoWidget::get_parent_bg ()
118 {
119         Widget* parent;
120
121         parent = get_parent ();
122
123         while (parent && !parent->get_has_window()) {
124                 parent = parent->get_parent();
125         }
126
127         if (parent && parent->get_has_window()) {
128                 return parent->get_style ()->get_bg (parent->get_state());
129         } 
130
131         return get_style ()->get_bg (get_state());
132 }
133
134 void
135 CairoWidget::set_active_state (CairoWidget::ActiveState s)
136 {
137         if (_active_state != s) {
138                 _active_state = s;
139                 StateChanged ();
140         }
141 }
142
143 void
144 CairoWidget::set_visual_state (CairoWidget::VisualState s)
145 {
146         if (_visual_state != s) {
147                 _visual_state = s;
148                 StateChanged ();
149         }
150 }