Ever so slightly less memory and better field alignment per CairoWidget.
[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         , _pixmap (0)
29         , _dirty (true)
30 {
31
32 }
33
34 CairoWidget::~CairoWidget ()
35 {
36         if (_pixmap) {
37                 g_object_unref (_pixmap);
38         }
39 }
40
41 bool
42 CairoWidget::on_expose_event (GdkEventExpose *event)
43 {
44         Gdk::Rectangle const exposure (
45                 event->area.x, event->area.y, event->area.width, event->area.height
46                 );
47
48         Gdk::Rectangle r = exposure;
49         Gdk::Rectangle content (0, 0, _width, _height);
50         bool intersects;
51         r.intersect (content, intersects);
52
53         if (intersects) {
54
55                 GdkDrawable* drawable = get_window()->gobj ();
56
57                 if (_dirty) {
58
59                         if (_pixmap) {
60                                 g_object_unref (_pixmap);
61                         }
62
63                         _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
64
65                         cairo_t* cr = gdk_cairo_create (_pixmap);
66                         render (cr);
67                         cairo_destroy (cr);
68
69                         _dirty = false;
70                 }
71
72                 gdk_draw_drawable (
73                         drawable,
74                         get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
75                         _pixmap,
76                         r.get_x(),
77                         r.get_y(),
78                         r.get_x(),
79                         r.get_y(),
80                         r.get_width(),
81                         r.get_height()
82                         );
83         }
84
85         return true;
86 }
87
88 /** Marks the widget as dirty, so that render () will be called on
89  *  the next GTK expose event.
90  */
91
92 void
93 CairoWidget::set_dirty ()
94 {
95         ENSURE_GUI_THREAD (*this, &CairoWidget::set_dirty)
96
97         _dirty = true;
98         queue_draw ();
99 }
100
101 /** Handle a size allocation.
102  *  @param alloc GTK allocation.
103  */
104 void
105 CairoWidget::on_size_allocate (Gtk::Allocation& alloc)
106 {
107         Gtk::EventBox::on_size_allocate (alloc);
108
109         _width = alloc.get_width ();
110         _height = alloc.get_height ();
111
112         set_dirty ();
113 }
114
115 Gdk::Color
116 CairoWidget::get_parent_bg ()
117 {
118         Widget* parent;
119
120         parent = get_parent ();
121
122         while (parent && !parent->get_has_window()) {
123                 parent = parent->get_parent();
124         }
125
126         if (parent && parent->get_has_window()) {
127                 return parent->get_style ()->get_bg (parent->get_state());
128         } 
129
130         return get_style ()->get_bg (get_state());
131 }
132
133 void
134 CairoWidget::set_active_state (CairoWidget::ActiveState s)
135 {
136         if (_active_state != s) {
137                 _active_state = s;
138                 StateChanged ();
139         }
140 }
141
142 void
143 CairoWidget::set_visual_state (CairoWidget::VisualState s)
144 {
145         if (_visual_state != s) {
146                 _visual_state = s;
147                 StateChanged ();
148         }
149 }