ardour
cairo_widget.cc
Go to the documentation of this file.
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 #if !defined USE_CAIRO_IMAGE_SURFACE && !defined NDEBUG
20 #define OPTIONAL_CAIRO_IMAGE_SURFACE
21 #endif
22 
23 #include "gtkmm2ext/cairo_widget.h"
24 #include "gtkmm2ext/gui_thread.h"
25 
26 #include "i18n.h"
27 
28 static const char* has_cairo_widget_background_info = "has_cairo_widget_background_info";
29 
30 bool CairoWidget::_flat_buttons = false;
32 
33 static void noop() { }
34 sigc::slot<void> CairoWidget::focus_handler (sigc::ptr_fun (noop));
35 
36 void CairoWidget::set_source_rgb_a( cairo_t* cr, Gdk::Color col, float a) //ToDo: this one and the Canvas version should be in a shared file (?)
37 {
38  float r = col.get_red_p ();
39  float g = col.get_green_p ();
40  float b = col.get_blue_p ();
41 
42  cairo_set_source_rgba(cr, r, g, b, a);
43 }
44 
46  : _active_state (Gtkmm2ext::Off)
47  , _visual_state (Gtkmm2ext::NoVisualState)
48  , _need_bg (true)
49  , _grabbed (false)
50  , _name_proxy (this, X_("name"))
51  , _current_parent (0)
52 {
53  _name_proxy.connect (sigc::mem_fun (*this, &CairoWidget::on_name_changed));
54 }
55 
57 {
59 }
60 
61 bool
63 {
64  focus_handler();
65  return false;
66 }
67 
68 bool
69 CairoWidget::on_expose_event (GdkEventExpose *ev)
70 {
71 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
72  Cairo::RefPtr<Cairo::Context> cr;
73  if (getenv("ARDOUR_IMAGE_SURFACE")) {
74  if (!image_surface) {
75  image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
76  }
77  cr = Cairo::Context::create (image_surface);
78  } else {
79  cr = get_window()->create_cairo_context ();
80  }
81 #elif defined USE_CAIRO_IMAGE_SURFACE
82 
83  if (!image_surface) {
84  image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
85  }
86 
87  Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create (image_surface);
88 #else
89  Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context ();
90 #endif
91 
92  cr->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
93  cr->clip_preserve ();
94 
95  /* paint expose area the color of the parent window bg
96  */
97 
98  Gdk::Color bg (get_parent_bg());
99 
100  cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
101  cr->fill ();
102 
103  cairo_rectangle_t expose_area;
104  expose_area.x = ev->area.x;
105  expose_area.y = ev->area.y;
106  expose_area.width = ev->area.width;
107  expose_area.height = ev->area.height;
108 
109  render (cr->cobj(), &expose_area);
110 
111 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
112  if (getenv("ARDOUR_IMAGE_SURFACE")) {
113 #endif
114 #if defined USE_CAIRO_IMAGE_SURFACE || defined OPTIONAL_CAIRO_IMAGE_SURFACE
115  image_surface->flush();
116  /* now blit our private surface back to the GDK one */
117 
118  Cairo::RefPtr<Cairo::Context> cairo_context = get_window()->create_cairo_context ();
119 
120  cairo_context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
121  cairo_context->clip ();
122  cairo_context->set_source (image_surface, 0, 0);
123  cairo_context->set_operator (Cairo::OPERATOR_SOURCE);
124  cairo_context->paint ();
125 #endif
126 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
127  }
128 #endif
129 
130  return true;
131 }
132 
137 void
139 {
141  queue_draw ();
142 }
143 
147 void
148 CairoWidget::on_size_allocate (Gtk::Allocation& alloc)
149 {
150  Gtk::EventBox::on_size_allocate (alloc);
151 
152 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
153  if (getenv("ARDOUR_IMAGE_SURFACE")) {
154 #endif
155 #if defined USE_CAIRO_IMAGE_SURFACE || defined OPTIONAL_CAIRO_IMAGE_SURFACE
156  image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, alloc.get_width(), alloc.get_height());
157 #endif
158 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
159  }
160 #endif
161 
162  set_dirty ();
163 }
164 
165 Gdk::Color
167 {
168  Widget* parent;
169 
170  parent = get_parent ();
171 
172  while (parent) {
173  void* p = g_object_get_data (G_OBJECT(parent->gobj()), has_cairo_widget_background_info);
174 
175  if (p) {
176  Glib::RefPtr<Gtk::Style> style = parent->get_style();
177  if (_current_parent != parent) {
178  if (_parent_style_change) _parent_style_change.disconnect();
179  _current_parent = parent;
180  _parent_style_change = parent->signal_style_changed().connect (mem_fun (*this, &CairoWidget::on_style_changed));
181  }
182  return style->get_bg (get_state());
183  }
184 
185  if (!parent->get_has_window()) {
186  parent = parent->get_parent();
187  } else {
188  break;
189  }
190  }
191 
192  if (parent && parent->get_has_window()) {
193  if (_current_parent != parent) {
194  if (_parent_style_change) _parent_style_change.disconnect();
195  _current_parent = parent;
196  _parent_style_change = parent->signal_style_changed().connect (mem_fun (*this, &CairoWidget::on_style_changed));
197  }
198  return parent->get_style ()->get_bg (parent->get_state());
199  }
200 
201  return get_style ()->get_bg (get_state());
202 }
203 
204 void
205 CairoWidget::set_active_state (Gtkmm2ext::ActiveState s)
206 {
207  if (_active_state != s) {
208  _active_state = s;
209  StateChanged ();
210  }
211 }
212 
213 void
214 CairoWidget::set_visual_state (Gtkmm2ext::VisualState s)
215 {
216  if (_visual_state != s) {
217  _visual_state = s;
218  StateChanged ();
219  }
220 }
221 
222 void
224 {
225  /* this is an API simplification for buttons
226  that only use the Active and Normal states.
227  */
228 
229  if (yn) {
231  } else {
233  }
234 }
235 
236 void
237 CairoWidget::on_style_changed (const Glib::RefPtr<Gtk::Style>&)
238 {
239  queue_draw();
240 }
241 
242 void
244 {
245  /* this will catch GTK-level state changes from calls like
246  ::set_sensitive()
247  */
248 
249  if (get_state() == Gtk::STATE_INSENSITIVE) {
250  set_visual_state (Gtkmm2ext::VisualState (visual_state() | Gtkmm2ext::Insensitive));
251  } else {
252  set_visual_state (Gtkmm2ext::VisualState (visual_state() & ~Gtkmm2ext::Insensitive));
253  }
254 
255  queue_draw ();
256 }
257 
258 void
260 {
261  _need_bg = yn;
262 }
263 
264 void
265 CairoWidget::provide_background_for_cairo_widget (Gtk::Widget& w, const Gdk::Color& bg)
266 {
267  /* set up @w to be able to provide bg information to
268  any CairoWidgets that are packed inside it.
269  */
270 
271  w.modify_bg (Gtk::STATE_NORMAL, bg);
272  w.modify_bg (Gtk::STATE_INSENSITIVE, bg);
273  w.modify_bg (Gtk::STATE_ACTIVE, bg);
274  w.modify_bg (Gtk::STATE_SELECTED, bg);
275 
276  g_object_set_data (G_OBJECT(w.gobj()), has_cairo_widget_background_info, (void*) 0xfeedface);
277 }
278 
279 void
281 {
282  _flat_buttons = yn;
283 }
284 
285 void
287 {
288  _widget_prelight = yn;
289 }
290 
291 void
292 CairoWidget::set_focus_handler (sigc::slot<void> s)
293 {
294  focus_handler = s;
295 }
Cairo::RefPtr< Cairo::Surface > image_surface
Definition: cairo_widget.h:124
virtual void render(cairo_t *, cairo_rectangle_t *)=0
static void noop()
Definition: cairo_widget.cc:33
static void set_focus_handler(sigc::slot< void >)
sigc::connection _parent_style_change
Definition: cairo_widget.h:126
virtual void set_active_state(Gtkmm2ext::ActiveState)
sigc::signal< void > StateChanged
Definition: cairo_widget.h:67
void unset_active_state()
Definition: cairo_widget.h:50
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
static void set_widget_prelight(bool yn)
static const char * has_cairo_widget_background_info
Definition: cairo_widget.cc:28
static sigc::slot< void > focus_handler
Definition: cairo_widget.h:121
static void set_source_rgb_a(cairo_t *cr, Gdk::Color, float a=1.0)
Definition: cairo_widget.cc:36
NoVisualState
Definition: widget_state.h:20
void set_draw_background(bool yn)
bool on_button_press_event(GdkEventButton *)
Definition: cairo_widget.cc:62
static void set_flat_buttons(bool yn)
#define X_(Text)
Definition: i18n.h:13
ExplicitActive
Definition: widget_state.h:13
Gtkmm2ext::VisualState visual_state() const
Definition: cairo_widget.h:41
static bool _widget_prelight
Definition: cairo_widget.h:118
void on_state_changed(Gtk::StateType)
void set_dirty()
void on_style_changed(const Glib::RefPtr< Gtk::Style > &)
Gtkmm2ext::VisualState _visual_state
Definition: cairo_widget.h:114
Insensitive
Definition: widget_state.h:23
virtual bool on_expose_event(GdkEventExpose *)
Definition: cairo_widget.cc:69
void set_active(bool)
Gdk::Color get_parent_bg()
Glib::SignalProxyProperty _name_proxy
Definition: cairo_widget.h:125
static bool _flat_buttons
Definition: cairo_widget.h:117
virtual void set_visual_state(Gtkmm2ext::VisualState)
virtual ~CairoWidget()
Definition: cairo_widget.cc:56
Widget * _current_parent
Definition: cairo_widget.h:127
Off
Definition: widget_state.h:13
virtual void on_name_changed()
Definition: cairo_widget.h:111
Gtkmm2ext::ActiveState _active_state
Definition: cairo_widget.h:111
void on_size_allocate(Gtk::Allocation &)
static void provide_background_for_cairo_widget(Gtk::Widget &w, const Gdk::Color &bg)