1 /* thread index cell renderer:
2  *
3  * the heart of showing threads in a fancy / sexy way. renders a
4  * nice looking thread entry based on a notmuch thread object -
5  * preferably without loading the message file.
6  *
7  */
8 
9 # include <iostream>
10 # include <time.h>
11 
12 # include <gtkmm/image.h>
13 # include <boost/property_tree/ptree.hpp>
14 
15 # include <notmuch.h>
16 
17 # include "thread_index.hh"
18 # include "thread_index_list_cell_renderer.hh"
19 # include "db.hh"
20 # include "utils/utils.hh"
21 # include "crypto.hh"
22 # ifndef DISABLE_PLUGINS
23   # include "plugin/manager.hh"
24 # endif
25 
26 using namespace std;
27 using boost::property_tree::ptree;
28 
29 namespace Astroid {
30 
ThreadIndexListCellRenderer(ThreadIndex * _ti)31   ThreadIndexListCellRenderer::ThreadIndexListCellRenderer (ThreadIndex * _ti) {
32     ptree ti = astroid->config ("thread_index.cell");
33     hidden_tags = VectorUtils::split_and_trim (ti.get<string> ("hidden_tags"), ",");
34     std::sort (hidden_tags.begin (), hidden_tags.end ());
35 
36     thread_index = _ti;
37 
38     /* load font settings */
39     font_desc_string = ti.get<string> ("font_description");
40     if (font_desc_string == "" || font_desc_string == "default") {
41       auto settings = Gio::Settings::create ("org.gnome.desktop.interface");
42       font_desc_string = settings->get_string ("monospace-font-name");
43     }
44 
45     font_description = Pango::FontDescription (font_desc_string);
46 
47     /* https://developer.gnome.org/pangomm/stable/classPango_1_1FontDescription.html#details */
48     if (font_description.get_size () == 0) {
49       LOG (warn) << "thread_index.cell.font_description: no size specified, expect weird behaviour.";
50     }
51 
52     line_spacing  = ti.get<int> ("line_spacing");
53     date_len      = ti.get<int> ("date_length");
54     message_count_len = ti.get<int> ("message_count_length");
55     authors_len   = ti.get<int> ("authors_length");
56     tags_len      = ti.get<int> ("tags_length");
57 
58     subject_color = ti.get<string> ("subject_color");
59     subject_color_selected = ti.get<string> ("subject_color_selected");
60     background_color_selected = ti.get<string> ("background_color_selected");
61 
62     background_color_marked = ti.get<string> ("background_color_marked");
63     background_color_marked_selected = ti.get<string> ("background_color_marked_selected");
64 
65   }
66 
render_vfunc(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget & widget,const Gdk::Rectangle & background_area,const Gdk::Rectangle & cell_area,Gtk::CellRendererState flags)67   void ThreadIndexListCellRenderer::render_vfunc (
68       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
69       Gtk::Widget    &widget,
70       const Gdk::Rectangle & background_area,
71       const Gdk::Rectangle &cell_area,
72       Gtk::CellRendererState flags)
73   {
74     // calculate text width, we don't need to do this every time,
75     // but we need access to the context.
76     if (!height_set) {
77       refptr<Pango::Context> pango_cr = widget.create_pango_context ();
78       font_metrics = pango_cr->get_metrics (font_description);
79 
80       int char_width = font_metrics.get_approximate_char_width () / Pango::SCALE;
81       padding = char_width;
82 
83       content_height  = calculate_height (widget);
84       line_height     = content_height + line_spacing;
85       height_set = true;
86 
87       left_icons_size  = content_height - (2 * left_icons_padding);
88       left_icons_width = left_icons_size;
89 
90       date_start          = left_icons_width_n * left_icons_width +
91           (left_icons_width_n-1) * left_icons_padding + padding;
92       date_width          = char_width * date_len;
93       message_count_width = char_width * message_count_len;
94       message_count_start = date_start + date_width + padding;
95       authors_width       = char_width * authors_len;
96       authors_start       = message_count_start + message_count_width + padding;
97       tags_width          = char_width * tags_len;
98       tags_start          = authors_start + authors_width + padding;
99       subject_start       = tags_start + tags_width + padding;
100 
101       height              = content_height + line_spacing;
102     }
103 
104     if (thread->unread) {
105       font_description.set_weight (Pango::WEIGHT_BOLD);
106     } else {
107       font_description.set_weight (Pango::WEIGHT_NORMAL);
108     }
109 
110     render_background (cr, widget, background_area, flags);
111     render_date (cr, widget, cell_area); // returns height
112 
113     if (thread->total_messages > 1)
114       render_message_count (cr, widget, cell_area);
115 
116     render_authors (cr, widget, cell_area);
117 
118     tags_width = render_tags (cr, widget, cell_area, flags); // returns width
119     subject_start = tags_start + tags_width / Pango::SCALE + ((tags_width > 0) ? padding : 0);
120 
121     render_subject (cr, widget, cell_area, flags);
122 
123     /*
124     if (!last)
125       render_delimiter (cr, widget, cell_area);
126     */
127 
128     if (thread->flagged)
129       render_flagged (cr, widget, cell_area);
130 
131     if (thread->attachment)
132       render_attachment (cr, widget, cell_area);
133 
134     /*
135     if (marked)
136       render_marked (cr, widget, cell_area);
137     */
138 
139   }
140 
~ThreadIndexListCellRenderer()141   ThreadIndexListCellRenderer::~ThreadIndexListCellRenderer () {
142     LOG (debug) << "til cr: deconstruct.";
143   }
144 
render_background(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget &,const Gdk::Rectangle & background_area,Gtk::CellRendererState flags)145   void ThreadIndexListCellRenderer::render_background ( // {{{
146       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
147       Gtk::Widget & /* widget */,
148       const Gdk::Rectangle &background_area,
149       Gtk::CellRendererState flags) {
150 
151     int y = background_area.get_y ();
152     int x = background_area.get_x ();
153 
154     int w = background_area.get_width ();
155     int h = background_area.get_height ();
156 
157     Gdk::Color bg;
158     bool set = true;
159 
160     if ((flags & Gtk::CELL_RENDERER_SELECTED) != 0) {
161       if (!marked) {
162         if (background_color_selected.length () > 0) {
163           bg = Gdk::Color (background_color_selected);
164         } else {
165           set = false;
166         }
167       } else {
168         bg = Gdk::Color (background_color_marked_selected);
169       }
170     } else {
171       if (!marked) {
172         set = false;
173       } else {
174         bg = Gdk::Color (background_color_marked);
175       }
176     }
177 
178     if (set) {
179       cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
180 
181       cr->rectangle (x, y, w, h);
182       cr->fill ();
183     }
184   } // }}}
185 
186   /* render icons {{{ */
render_marked(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget &,const Gdk::Rectangle & cell_area)187   void ThreadIndexListCellRenderer::render_marked (
188       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
189       Gtk::Widget & /* widget */,
190       const Gdk::Rectangle &cell_area ) {
191 
192 
193     if (!marked_icon) {
194       Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
195       Glib::RefPtr<Gdk::Pixbuf> pixbuf = theme->load_icon (
196           "object-select-symbolic",
197           left_icons_size,
198           Gtk::ICON_LOOKUP_USE_BUILTIN  | Gtk::ICON_LOOKUP_FORCE_SIZE);
199 
200 
201       marked_icon = pixbuf->scale_simple (left_icons_size, left_icons_size,
202           Gdk::INTERP_BILINEAR);
203     }
204 
205     int y = cell_area.get_y() + left_icons_padding + line_spacing / 2;
206     int x = cell_area.get_x();
207 
208     Gdk::Cairo::set_source_pixbuf (cr, marked_icon, x, y);
209 
210     cr->rectangle (x, y, left_icons_size, left_icons_size);
211     cr->fill ();
212   }
213 
render_flagged(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget &,const Gdk::Rectangle & cell_area)214   void ThreadIndexListCellRenderer::render_flagged (
215       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
216       Gtk::Widget & /* widget */,
217       const Gdk::Rectangle &cell_area ) {
218 
219 
220     if (!flagged_icon) {
221       Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
222       Glib::RefPtr<Gdk::Pixbuf> pixbuf = theme->load_icon (
223           "starred-symbolic",
224           left_icons_size,
225           Gtk::ICON_LOOKUP_USE_BUILTIN  | Gtk::ICON_LOOKUP_FORCE_SIZE);
226 
227       flagged_icon = pixbuf->scale_simple (left_icons_size, left_icons_size,
228           Gdk::INTERP_BILINEAR);
229     }
230 
231     int y = cell_area.get_y() + left_icons_padding + line_spacing / 2;
232     int x = cell_area.get_x() + 0 * (left_icons_width + left_icons_padding);
233 
234     Gdk::Cairo::set_source_pixbuf (cr, flagged_icon, x, y);
235 
236     cr->rectangle (x, y, left_icons_size,left_icons_size);
237     cr->fill ();
238   }
239 
240 
render_attachment(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget &,const Gdk::Rectangle & cell_area)241   void ThreadIndexListCellRenderer::render_attachment (
242       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
243       Gtk::Widget & /* widget */,
244       const Gdk::Rectangle &cell_area ) {
245 
246 
247     if (!attachment_icon) {
248       Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
249       Glib::RefPtr<Gdk::Pixbuf> pixbuf = theme->load_icon (
250           "mail-attachment-symbolic",
251           left_icons_size,
252           Gtk::ICON_LOOKUP_USE_BUILTIN | Gtk::ICON_LOOKUP_FORCE_SIZE);
253 
254 
255       attachment_icon = pixbuf->scale_simple (left_icons_size, left_icons_size,
256           Gdk::INTERP_BILINEAR);
257     }
258 
259     int y = cell_area.get_y() + left_icons_padding + line_spacing / 2;
260     int x = cell_area.get_x() + (1 * (left_icons_width + left_icons_padding));
261 
262     Gdk::Cairo::set_source_pixbuf (cr, attachment_icon, x, y);
263 
264     cr->rectangle (x, y, left_icons_size, left_icons_size);
265     cr->fill ();
266   } // }}}
267 
render_delimiter(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget &,const Gdk::Rectangle & cell_area)268   void ThreadIndexListCellRenderer::render_delimiter ( // {{{
269       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
270       Gtk::Widget & /*widget */,
271       const Gdk::Rectangle &cell_area ) {
272 
273     cr->set_line_width(0.5);
274     Gdk::Color gray;
275     gray.set_grey_p (0.1);
276     cr->set_source_rgb (gray.get_red_p(), gray.get_green_p(), gray.get_blue_p());
277 
278     cr->move_to(cell_area.get_x(), cell_area.get_y() + cell_area.get_height());
279     cr->line_to(cell_area.get_x() + cell_area.get_width(), cell_area.get_y() + cell_area.get_height());
280     cr->stroke ();
281 
282   } // }}}
283 
render_subject(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget & widget,const Gdk::Rectangle & cell_area,Gtk::CellRendererState flags)284   void ThreadIndexListCellRenderer::render_subject ( // {{{
285       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
286       Gtk::Widget &widget,
287       const Gdk::Rectangle &cell_area,
288       Gtk::CellRendererState flags) {
289 
290     Glib::RefPtr<Pango::Layout> pango_layout = widget.create_pango_layout ("");
291 
292     pango_layout->set_font_description (font_description);
293 
294     /* set color */
295     Glib::RefPtr<Gtk::StyleContext> stylecontext = widget.get_style_context();
296 
297     Gdk::RGBA color = stylecontext->get_color(Gtk::STATE_FLAG_NORMAL);
298     cr->set_source_rgb (color.get_red(), color.get_green(), color.get_blue());
299     ustring color_str;
300     if ((flags & Gtk::CELL_RENDERER_SELECTED) != 0) {
301       color_str = subject_color_selected;
302     } else {
303       color_str = subject_color;
304     }
305 
306     pango_layout->set_markup (ustring::compose ("<span color=\"%1\">%2</span>",
307         color_str,
308         Glib::Markup::escape_text(thread->subject)));
309 
310     /* align in the middle */
311     int w, h;
312     pango_layout->get_size (w, h);
313     int y = max(0,(line_height / 2) - ((h / Pango::SCALE) / 2));
314 
315     cr->move_to (cell_area.get_x() + subject_start, cell_area.get_y() + y);
316     pango_layout->show_in_cairo_context (cr);
317 
318   } // }}}
319 
render_tags(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget & widget,const Gdk::Rectangle & cell_area,Gtk::CellRendererState flags)320   int ThreadIndexListCellRenderer::render_tags ( // {{{
321       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
322       Gtk::Widget &widget,
323       const Gdk::Rectangle &cell_area,
324       Gtk::CellRendererState flags) {
325 
326     Glib::RefPtr<Pango::Layout> pango_layout = widget.create_pango_layout ("");
327 
328     pango_layout->set_font_description (font_description);
329 
330     /* set color */
331     Glib::RefPtr<Gtk::StyleContext> stylecontext = widget.get_style_context();
332 
333     Gdk::RGBA color = stylecontext->get_color(Gtk::STATE_FLAG_NORMAL);
334     cr->set_source_rgb (color.get_red(), color.get_green(), color.get_blue());
335 
336     /* subtract hidden tags */
337     vector<ustring> tags;
338     set_difference (thread->tags.begin(),
339                     thread->tags.end(),
340                     hidden_tags.begin (),
341                     hidden_tags.end (),
342                     back_inserter(tags));
343 
344     ustring tag_string;
345 
346     Gdk::Color bg;
347 
348     if ((flags & Gtk::CELL_RENDERER_SELECTED) != 0) {
349       bg = Gdk::Color (background_color_selected);
350       cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
351     } else {
352       bg.set_grey_p (1.);
353     }
354 
355     /* first try plugin */
356 # ifndef DISABLE_PLUGINS
357     if (!thread_index->plugins->format_tags (tags, bg.to_string (), (flags & Gtk::CELL_RENDERER_SELECTED) != 0, tag_string)) {
358 # endif
359 
360       unsigned char cv[3] = { (unsigned char) bg.get_red (),
361                               (unsigned char) bg.get_green (),
362                               (unsigned char) bg.get_blue () };
363 
364       tag_string = VectorUtils::concat_tags_color (tags, true, tags_len, cv);
365 # ifndef DISABLE_PLUGINS
366     }
367 # endif
368 
369     pango_layout->set_markup (tag_string);
370 
371     /* align in the middle */
372     int w, h;
373     pango_layout->get_size (w, h);
374     int y = max(0,(line_height / 2) - ((h / Pango::SCALE) / 2));
375 
376     cr->move_to (cell_area.get_x() + tags_start, cell_area.get_y() + y);
377     pango_layout->show_in_cairo_context (cr);
378 
379     return w;
380 
381   } // }}}
382 
render_date(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget & widget,const Gdk::Rectangle & cell_area)383   int ThreadIndexListCellRenderer::render_date ( // {{{
384       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
385       Gtk::Widget &widget,
386       const Gdk::Rectangle &cell_area ) {
387 
388     ustring date = Date::pretty_print (thread->newest_date);
389 
390     Glib::RefPtr<Pango::Layout> pango_layout = widget.create_pango_layout (date);
391 
392     pango_layout->set_font_description (font_description);
393 
394     /* set color */
395     Glib::RefPtr<Gtk::StyleContext> stylecontext = widget.get_style_context();
396     Gdk::RGBA color = stylecontext->get_color(Gtk::STATE_FLAG_NORMAL);
397     cr->set_source_rgb (color.get_red(), color.get_green(), color.get_blue());
398 
399     /* align in the middle */
400     int w, h;
401     pango_layout->get_size (w, h);
402     int y = max(0,(line_height / 2) - ((h / Pango::SCALE) / 2));
403 
404     /* update subject start */
405     //subject_start = date_start + (w / Pango::SCALE) + padding;
406 
407     cr->move_to (cell_area.get_x() + date_start, cell_area.get_y() + y);
408     pango_layout->show_in_cairo_context (cr);
409 
410     return h; // return height!
411 
412   } // }}}
413 
render_message_count(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget & widget,const Gdk::Rectangle & cell_area)414   void ThreadIndexListCellRenderer::render_message_count ( // {{{
415       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
416       Gtk::Widget &widget,
417       const Gdk::Rectangle &cell_area ) {
418 
419 # define BUFLEN 24
420     char buf[BUFLEN];
421     snprintf (buf, BUFLEN, "(%d)", thread->total_messages);
422 
423 
424     Glib::RefPtr<Pango::Layout> pango_layout = widget.create_pango_layout (buf);
425 
426     pango_layout->set_font_description (font_description);
427 
428     /* set color */
429     Glib::RefPtr<Gtk::StyleContext> stylecontext = widget.get_style_context();
430     Gdk::RGBA color = stylecontext->get_color(Gtk::STATE_FLAG_NORMAL);
431     cr->set_source_rgb (color.get_red(), color.get_green(), color.get_blue());
432 
433     /* align in the middle */
434     int w, h;
435     pango_layout->get_size (w, h);
436     int y = max(0,(line_height / 2) - ((h / Pango::SCALE) / 2));
437 
438     /* update subject start */
439     //subject_start = date_start + (w / Pango::SCALE) + padding;
440 
441     cr->move_to (cell_area.get_x() + message_count_start, cell_area.get_y() + y);
442     pango_layout->show_in_cairo_context (cr);
443 
444   } // }}}
445 
render_authors(const::Cairo::RefPtr<::Cairo::Context> & cr,Gtk::Widget & widget,const Gdk::Rectangle & cell_area)446   void ThreadIndexListCellRenderer::render_authors ( // {{{
447       const ::Cairo::RefPtr< ::Cairo::Context>&cr,
448       Gtk::Widget &widget,
449       const Gdk::Rectangle &cell_area ) {
450 
451     /* format authors string */
452     ustring authors;
453 
454     if (thread->authors.size () == 1) {
455       /* if only one, show full name */
456       ustring an = get<0>(thread->authors[0]);
457 
458       if (static_cast<int>(an.size()) >= authors_len) {
459         an = an.substr (0, authors_len);
460         UstringUtils::trim_right(an);
461         an += ".";
462       }
463 
464       if (get<1>(thread->authors[0])) {
465         authors = ustring::compose ("<b>%1</b>",
466           Glib::Markup::escape_text (an));
467       } else {
468         authors = Glib::Markup::escape_text (an);
469       }
470 
471     } else {
472       /* show first names separated by comma */
473       bool first = true;
474 
475       int len = 0;
476       for (auto &a : thread->authors) {
477         if (!first) len += 1; // comma
478 
479         ustring an = get<0>(a);
480 
481         size_t pos = an.find_first_of (",. @");
482         if (an[pos] == ',' || an[pos] == '.') { // last name, first name format or initial/title.
483             an = an.substr (pos + 1, an.size ());
484             UstringUtils::trim_left (an);
485             pos = an.find_first_of (" @");
486             an = an.substr (0, pos);
487         } else {
488             an = an.substr (0, pos);
489         }
490 
491         int tlen = static_cast<int>(an.size());
492         if ((len + tlen) >= authors_len) {
493           an = an.substr (0, authors_len - len);
494           UstringUtils::trim_right (an);
495           an += ".";
496           tlen = authors_len - len;
497         }
498 
499         len += tlen;
500 
501         if (!first) {
502           authors += ",";
503         } else {
504           first = false;
505         }
506 
507         if (get<1>(a)) {
508           authors += ustring::compose ("<b>%1</b>", Glib::Markup::escape_text (an));
509         } else {
510           authors += Glib::Markup::escape_text (an);
511         }
512 
513 
514         if (len >= authors_len) {
515           break;
516         }
517       }
518     }
519 
520 
521     Glib::RefPtr<Pango::Layout> pango_layout = widget.create_pango_layout ("");
522     pango_layout->set_markup (authors);
523 
524     if (thread->unread) {
525       font_description.set_weight (Pango::WEIGHT_NORMAL);
526     }
527 
528     pango_layout->set_font_description (font_description);
529 
530     if (thread->unread) {
531       font_description.set_weight (Pango::WEIGHT_BOLD);
532     }
533 
534     /* set color */
535     Glib::RefPtr<Gtk::StyleContext> stylecontext = widget.get_style_context();
536     Gdk::RGBA color = stylecontext->get_color(Gtk::STATE_FLAG_NORMAL);
537     cr->set_source_rgb (color.get_red(), color.get_green(), color.get_blue());
538 
539     /* align in the middle */
540     int w, h;
541     pango_layout->get_size (w, h);
542     int y = max(0,(line_height / 2) - ((h / Pango::SCALE) / 2));
543 
544     /* update subject start */
545     //subject_start = date_start + (w / Pango::SCALE) + padding;
546 
547     cr->move_to (cell_area.get_x() + authors_start, cell_area.get_y() + y);
548     pango_layout->show_in_cairo_context (cr);
549 
550   } // }}}
551 
552   /* cellrenderer overloads {{{ */
get_height()553   int ThreadIndexListCellRenderer::get_height () {
554     if (height_set) return line_height;
555     else return 0;
556   }
557 
calculate_height(Gtk::Widget & widget) const558   int ThreadIndexListCellRenderer::calculate_height (Gtk::Widget &widget) const {
559     if (height_set) return content_height;
560 
561     /* figure out font height */
562     Glib::RefPtr<Pango::Layout> pango_layout = widget.create_pango_layout ("TEST HEIGHT STRING");
563 
564     pango_layout->set_font_description (font_description);
565 
566     int w, h;
567     pango_layout->get_pixel_size (w, h);
568 
569     int content_height = h;
570 
571     return content_height;
572   }
573 
get_request_mode_vfunc() const574   Gtk::SizeRequestMode ThreadIndexListCellRenderer::get_request_mode_vfunc () const {
575     return Gtk::SIZE_REQUEST_CONSTANT_SIZE;
576   }
577 
get_preferred_height_vfunc(Gtk::Widget & widget,int & minimum_height,int & natural_height) const578   void ThreadIndexListCellRenderer::get_preferred_height_vfunc (
579       Gtk::Widget& widget,
580       int& minimum_height,
581       int& natural_height) const {
582 
583     int height = calculate_height (widget) + line_spacing;
584 
585     minimum_height = height;
586     natural_height = height;
587   }
588 
get_preferred_height_for_width_vfunc(Gtk::Widget & widget,int,int & minimum_height,int & natural_height) const589   void ThreadIndexListCellRenderer::get_preferred_height_for_width_vfunc (
590       Gtk::Widget& widget,
591       int /* width */,
592       int& minimum_height,
593       int& natural_height) const {
594 
595     /* wrap non-width dependent */
596     get_preferred_height_vfunc (widget, minimum_height, natural_height);
597 
598   }
599 
get_preferred_width_vfunc(Gtk::Widget &,int & minimum_width,int & natural_width) const600   void ThreadIndexListCellRenderer::get_preferred_width_vfunc (
601       Gtk::Widget& /* widget*/,
602       int& minimum_width,
603       int& natural_width) const {
604 
605     minimum_width = 100;
606     natural_width = minimum_width;
607   }
608 
activate_vfunc(GdkEvent *,Gtk::Widget &,const Glib::ustring &,const Gdk::Rectangle &,const Gdk::Rectangle &,Gtk::CellRendererState)609   bool ThreadIndexListCellRenderer::activate_vfunc(
610       GdkEvent* /* event */,
611       Gtk::Widget& /* widget */,
612       const Glib::ustring& /* path */,
613       const Gdk::Rectangle& /* background_area */,
614       const Gdk::Rectangle& /* cell_area */,
615       Gtk::CellRendererState /* flags */)
616   {
617     return false;
618   }
619   // }}}
620 
621 }
622 
623