Merge branch 'windows+cc' into cairocanvas
[ardour.git] / libs / gtkmm2ext / utils.cc
1 /*
2     Copyright (C) 1999 Paul Barton-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     $Id$
19 */
20
21 #include <map>
22
23 #include <gtk/gtkpaned.h>
24 #include <gtk/gtk.h>
25
26 #include <gtkmm/widget.h>
27 #include <gtkmm/button.h>
28 #include <gtkmm/window.h>
29 #include <gtkmm/paned.h>
30 #include <gtkmm/label.h>
31 #include <gtkmm/comboboxtext.h>
32 #include <gtkmm/tooltip.h>
33
34 #include "gtkmm2ext/utils.h"
35
36 #include "i18n.h"
37
38 using namespace std;
39
40 void
41 Gtkmm2ext::init (const char* localedir)
42 {
43 #ifdef ENABLE_NLS
44         (void) bindtextdomain(PACKAGE, localedir);
45 #endif
46 }
47
48 void
49 Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
50                                int& width,
51                                int& height)
52 {
53         Pango::Rectangle ink_rect = layout->get_ink_extents ();
54         
55         width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
56         height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
57 }
58
59 void
60 Gtkmm2ext::get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
61                            int& width,
62                            int& height)
63 {
64         layout->get_pixel_size (width, height);
65 }
66
67 void
68 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
69                                                    gint hpadding, gint vpadding)
70 {
71         int width, height;
72         w.ensure_style ();
73         
74         get_pixel_size (w.create_pango_layout (text), width, height);
75         w.set_size_request(width + hpadding, height + vpadding);
76 }
77
78 void
79 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, 
80                                                    const std::vector<std::string>& strings,
81                                                    gint hpadding, gint vpadding)
82 {
83         int width, height;
84         int width_max = 0;
85         int height_max = 0;
86         w.ensure_style ();
87         vector<string> copy;
88         const vector<string>* to_use;
89         vector<string>::const_iterator i;
90
91         for (i = strings.begin(); i != strings.end(); ++i) {
92                 if ((*i).find_first_of ("gy") != string::npos) {
93                         /* contains a descender */
94                         break;
95                 }
96         }
97         
98         if (i == strings.end()) {
99                 /* make a copy of the strings then add one that has a descender */
100                 copy = strings;
101                 copy.push_back ("g");
102                 to_use = &copy;
103         } else {
104                 to_use = &strings;
105         }
106         
107         for (vector<string>::const_iterator i = to_use->begin(); i != to_use->end(); ++i) {
108                 get_pixel_size (w.create_pango_layout (*i), width, height);
109                 width_max = max(width_max,width);
110                 height_max = max(height_max, height);
111         }
112
113         w.set_size_request(width_max + hpadding, height_max + vpadding);
114 }
115
116 static inline guint8
117 demultiply_alpha (guint8 src,
118                   guint8 alpha)
119 {
120         /* cairo pixel buffer data contains RGB values with the alpha
121            values premultiplied.
122
123            GdkPixbuf pixel buffer data contains RGB values without the
124            alpha value applied.
125
126            this removes the alpha component from the cairo version and
127            returns the GdkPixbuf version.
128         */
129         return alpha ? ((guint (src) << 8) - src) / alpha : 0;
130 }
131
132 void
133 Gtkmm2ext::convert_bgra_to_rgba (guint8 const* src,
134                                  guint8*       dst,
135                                  int           width,
136                                  int           height)
137 {
138         guint8 const* src_pixel = src;
139         guint8*       dst_pixel = dst;
140         
141         /* cairo pixel data is endian-dependent ARGB with A in the most significant 8 bits,
142            with premultipled alpha values (see preceding function)
143
144            GdkPixbuf pixel data is non-endian-dependent RGBA with R in the lowest addressable
145            8 bits, and non-premultiplied alpha values.
146
147            convert from the cairo values to the GdkPixbuf ones.
148         */
149
150         for (int y = 0; y < height; y++) {
151                 for (int x = 0; x < width; x++) {
152 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
153                         /* Cairo [ B G R A ] is actually  [ B G R A ] in memory SOURCE
154                                                             0 1 2 3
155                            Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
156                         */
157                         dst_pixel[0] = demultiply_alpha (src_pixel[2],
158                                                          src_pixel[3]); // R [0] <= [ 2 ]
159                         dst_pixel[1] = demultiply_alpha (src_pixel[1],
160                                                          src_pixel[3]); // G [1] <= [ 1 ]
161                         dst_pixel[2] = demultiply_alpha (src_pixel[0],  
162                                                          src_pixel[3]); // B [2] <= [ 0 ]
163                         dst_pixel[3] = src_pixel[3]; // alpha
164                         
165 #elif G_BYTE_ORDER == G_BIG_ENDIAN
166                         /* Cairo [ B G R A ] is actually  [ A R G B ] in memory SOURCE
167                                                             0 1 2 3
168                            Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
169                         */
170                         dst_pixel[0] = demultiply_alpha (src_pixel[1],
171                                                          src_pixel[0]); // R [0] <= [ 1 ]
172                         dst_pixel[1] = demultiply_alpha (src_pixel[2],
173                                                          src_pixel[0]); // G [1] <= [ 2 ]
174                         dst_pixel[2] = demultiply_alpha (src_pixel[3],
175                                                          src_pixel[0]); // B [2] <= [ 3 ]
176                         dst_pixel[3] = src_pixel[0]; // alpha
177                         
178 #else
179 #error ardour does not currently support PDP-endianess
180 #endif                  
181                         
182                         dst_pixel += 4;
183                         src_pixel += 4;
184                 }
185         }
186 }
187
188 Glib::RefPtr<Gdk::Pixbuf>
189 Gtkmm2ext::pixbuf_from_string(const string& name, const Pango::FontDescription& font, int clip_width, int clip_height, Gdk::Color fg)
190 {
191         static Glib::RefPtr<Gdk::Pixbuf>* empty_pixbuf = 0;
192
193         if (name.empty()) {
194                 if (empty_pixbuf == 0) {
195                         empty_pixbuf = new Glib::RefPtr<Gdk::Pixbuf>;
196                         *empty_pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
197                 }
198                 return *empty_pixbuf;
199         }
200
201         Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
202
203         cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
204         cairo_t* cr = cairo_create (surface);
205         cairo_text_extents_t te;
206         
207         cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0);
208         cairo_select_font_face (cr, font.get_family().c_str(),
209                                 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
210         cairo_set_font_size (cr,  font.get_size() / Pango::SCALE);
211         cairo_text_extents (cr, name.c_str(), &te);
212         
213         cairo_move_to (cr, 0.5, int (0.5 - te.height / 2 - te.y_bearing + clip_height / 2));
214         cairo_show_text (cr, name.c_str());
215         
216         convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
217
218         cairo_destroy(cr);
219         cairo_surface_destroy(surface);
220
221         return buf;
222 }
223
224 void
225 Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings)
226 {
227         vector<string>::const_iterator i;
228
229         cr.clear ();
230
231         for (i = strings.begin(); i != strings.end(); ++i) {
232                 cr.append_text (*i);
233         }
234 }
235
236 GdkWindow*
237 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
238 {
239         return GTK_PANED(paned.gobj())->handle;
240 }
241
242 void
243 Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
244 {
245         win->get_window()->set_decorations (decor);
246 }
247
248 void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
249 {
250         gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
251 }
252
253 void
254 Gtkmm2ext::detach_menu (Gtk::Menu& menu)
255 {
256         /* its possible for a Gtk::Menu to have no gobj() because it has
257            not yet been instantiated. Catch this and provide a safe
258            detach method.
259         */
260         if (menu.gobj()) {
261                 if (menu.get_attach_widget()) {
262                         menu.detach ();
263                 }
264         }
265 }
266
267 bool
268 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
269 {
270         int fakekey = GDK_VoidSymbol;
271
272         switch (keyval) {
273         case GDK_Tab:
274         case GDK_ISO_Left_Tab:
275                 fakekey = GDK_nabla;
276                 break;
277
278         case GDK_Up:
279                 fakekey = GDK_uparrow;
280                 break;
281
282         case GDK_Down:
283                 fakekey = GDK_downarrow;
284                 break;
285
286         case GDK_Right:
287                 fakekey = GDK_rightarrow;
288                 break;
289
290         case GDK_Left:
291                 fakekey = GDK_leftarrow;
292                 break;
293
294         case GDK_Return:
295                 fakekey = GDK_3270_Enter;
296                 break;
297
298         case GDK_KP_Enter:
299                 fakekey = GDK_F35;
300                 break;
301
302         default:
303                 break;
304         }
305
306         if (fakekey != GDK_VoidSymbol) {
307                 keyval = fakekey;
308                 return true;
309         }
310
311         return false;
312 }
313
314 uint32_t
315 Gtkmm2ext::possibly_translate_legal_accelerator_to_real_key (uint32_t keyval)
316 {
317         switch (keyval) {
318         case GDK_nabla:
319                 return GDK_Tab;
320                 break;
321
322         case GDK_uparrow:
323                 return GDK_Up;
324                 break;
325
326         case GDK_downarrow:
327                 return GDK_Down;
328                 break;
329
330         case GDK_rightarrow:
331                 return GDK_Right;
332                 break;
333
334         case GDK_leftarrow:
335                 return GDK_Left;
336                 break;
337
338         case GDK_3270_Enter:
339                 return GDK_Return;
340
341         case GDK_F35:
342                 return GDK_KP_Enter;
343                 break;
344         }
345
346         return keyval;
347 }
348
349 int
350 Gtkmm2ext::physical_screen_height (Glib::RefPtr<Gdk::Window> win)
351 {
352         GdkScreen* scr = gdk_screen_get_default();
353
354         if (win) {
355                 GdkRectangle r;
356                 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
357                 gdk_screen_get_monitor_geometry (scr, monitor, &r);
358                 return r.height;
359         } else {
360                 return gdk_screen_get_height (scr);
361         }
362 }
363
364 int
365 Gtkmm2ext::physical_screen_width (Glib::RefPtr<Gdk::Window> win)
366 {
367         GdkScreen* scr = gdk_screen_get_default();
368         
369         if (win) {
370                 GdkRectangle r;
371                 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
372                 gdk_screen_get_monitor_geometry (scr, monitor, &r);
373                 return r.width;
374         } else {
375                 return gdk_screen_get_width (scr);
376         }
377 }
378
379 void
380 Gtkmm2ext::container_clear (Gtk::Container& c)
381 {
382         list<Gtk::Widget*> children = c.get_children();
383         for (list<Gtk::Widget*>::iterator child = children.begin(); child != children.end(); ++child) {
384                 c.remove (**child);
385         }
386 }
387
388 void
389 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
390 {
391         rounded_rectangle (context->cobj(), x, y, w, h, r);
392 }
393 void
394 Gtkmm2ext::rounded_top_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
395 {
396         rounded_top_rectangle (context->cobj(), x, y, w, h, r);
397 }
398 void
399 Gtkmm2ext::rounded_top_left_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
400 {
401         rounded_top_left_rectangle (context->cobj(), x, y, w, h, r);
402 }
403 void
404 Gtkmm2ext::rounded_top_right_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
405 {
406         rounded_top_right_rectangle (context->cobj(), x, y, w, h, r);
407 }
408 void
409 Gtkmm2ext::rounded_top_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
410 {
411         rounded_top_half_rectangle (context->cobj(), x, y, w, h, r);
412 }
413 void
414 Gtkmm2ext::rounded_bottom_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
415 {
416         rounded_bottom_half_rectangle (context->cobj(), x, y, w, h, r);
417 }
418
419 void
420 Gtkmm2ext::rounded_left_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
421 {
422         rounded_left_half_rectangle (context->cobj(), x, y, w, h, r);
423 }
424
425 void
426 Gtkmm2ext::rounded_right_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
427 {
428         rounded_right_half_rectangle (context->cobj(), x, y, w, h, r);
429 }
430
431 void
432 Gtkmm2ext::rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
433 {
434         double degrees = M_PI / 180.0;
435
436         cairo_new_sub_path (cr);
437         cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);  //tr
438         cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees);  //br
439         cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees);  //bl
440         cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees);  //tl
441         cairo_close_path (cr);
442 }
443
444 void
445 Gtkmm2ext::rounded_left_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
446 {
447         double degrees = M_PI / 180.0;
448
449         cairo_new_sub_path (cr);
450         cairo_line_to (cr, x+w, y); // tr
451         cairo_line_to (cr, x+w, y + h); // br
452         cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees);  //bl
453         cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees);  //tl
454         cairo_close_path (cr);
455 }
456
457 void
458 Gtkmm2ext::rounded_right_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
459 {
460         double degrees = M_PI / 180.0;
461
462         cairo_new_sub_path (cr);
463         cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);  //tr
464         cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees);  //br
465         cairo_line_to (cr, x, y + h); // bl
466         cairo_line_to (cr, x, y); // tl
467         cairo_close_path (cr);
468 }
469
470 void
471 Gtkmm2ext::rounded_top_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
472 {
473         double degrees = M_PI / 180.0;
474
475         cairo_new_sub_path (cr);
476         cairo_move_to (cr, x+w, y+h);
477         cairo_line_to (cr, x, y+h);
478         cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees);  //tl
479         cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);  //tr
480         cairo_close_path (cr);
481 }
482
483 void
484 Gtkmm2ext::rounded_bottom_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
485 {
486         double degrees = M_PI / 180.0;
487
488         cairo_new_sub_path (cr);
489         cairo_move_to (cr, x, y);
490         cairo_line_to (cr, x+w, y);
491         cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees);  //br
492         cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees);  //bl
493         cairo_close_path (cr);
494 }
495
496
497 void
498 Gtkmm2ext::rounded_top_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
499 {
500         double degrees = M_PI / 180.0;
501
502         cairo_new_sub_path (cr);
503         cairo_move_to (cr, x+w, y+h);
504         cairo_line_to (cr, x, y+h);
505         cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees);  //tl
506         cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);  //tr
507         cairo_close_path (cr);
508 }
509
510 void
511 Gtkmm2ext::rounded_top_left_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
512 {
513 /*    A****B
514       H    *
515       *    *
516       *    *
517       F****E
518 */
519         cairo_move_to (cr, x+r,y); // Move to A
520         cairo_line_to (cr, x+w,y); // Straight line to B
521         cairo_line_to (cr, x+w,y+h); // Move to E
522         cairo_line_to (cr, x,y+h); // Line to F
523         cairo_line_to (cr, x,y+r); // Line to H
524         cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
525 }
526
527 void
528 Gtkmm2ext::rounded_top_right_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
529 {
530 /*    A****BQ
531       *    C
532       *    *
533       *    *
534       F****E
535 */
536         cairo_move_to (cr, x,y); // Move to A
537         cairo_line_to (cr, x+w-r,y); // Straight line to B
538         cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
539         cairo_line_to (cr, x+w,y+h); // Move to E
540         cairo_line_to (cr, x,y+h); // Line to F
541         cairo_line_to (cr, x,y); // Line to A
542 }
543
544 Glib::RefPtr<Gdk::Window>
545 Gtkmm2ext::window_to_draw_on (Gtk::Widget& w, Gtk::Widget** parent)
546 {
547         if (w.get_has_window()) {
548                 return w.get_window();
549         }
550
551         (*parent) = w.get_parent();
552
553         while (*parent) {
554                 if ((*parent)->get_has_window()) {
555                         return (*parent)->get_window ();
556                 }
557                 (*parent) = (*parent)->get_parent ();
558         }
559
560         return Glib::RefPtr<Gdk::Window> ();
561 }
562
563 int
564 Gtkmm2ext::pixel_width (const string& str, Pango::FontDescription& font)
565 {
566         Gtk::Label foo;
567         Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
568
569         layout->set_font_description (font);
570         layout->set_text (str);
571
572         int width, height;
573         Gtkmm2ext::get_ink_pixel_size (layout, width, height);
574         return width;
575 }
576
577 #if 0
578 string
579 Gtkmm2ext::fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
580 {
581         /* DECEMBER 2011: THIS PROTOTYPE OF fit_to_pixels() IS NOT USED
582            ANYWHERE AND HAS NOT BEEN TESTED.
583         */
584         Gtk::Label foo;
585         Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (str);
586         Glib::RefPtr<const Pango::LayoutLine> line;
587
588         layout->set_font_description (font);
589         layout->set_width (pixel_width * PANGO_SCALE);
590
591         if (with_ellipses) {
592                 layout->set_ellipsize (Pango::ELLIPSIZE_END);
593         } else {
594                 layout->set_wrap (Pango::WRAP_CHAR);
595         }
596
597         line = layout->get_line (0);
598
599         /* XXX: might need special care to get the ellipsis character, not sure
600            how that works 
601         */      
602
603         string s = string (layout->get_text ().substr(line->get_start_index(), line->get_length()));
604         
605         cerr << "fit to pixels of " << str << " returns " << s << endl;
606
607         return s;
608 }
609 #endif
610
611 /** Try to fit a string into a given horizontal space by ellipsizing it.
612  *  @param cr Cairo context in which the text will be plotted.
613  *  @param name Text.
614  *  @param avail Available horizontal space.
615  *  @return (Text, possibly ellipsized) and (horizontal size of text)
616  */
617
618 std::pair<std::string, double>
619 Gtkmm2ext::fit_to_pixels (cairo_t* cr, std::string name, double avail)
620 {
621         /* XXX hopefully there exists a more efficient way of doing this */
622
623         bool abbreviated = false;
624         uint32_t width = 0;
625
626         while (1) {
627                 cairo_text_extents_t ext;
628                 cairo_text_extents (cr, name.c_str(), &ext);
629
630                 if (ext.width < avail || name.length() <= 4) {
631                         width = ext.width;
632                         break;
633                 }
634
635                 if (abbreviated) {
636                         name = name.substr (0, name.length() - 4) + "...";
637                 } else {
638                         name = name.substr (0, name.length() - 3) + "...";
639                         abbreviated = true;
640                 }
641         }
642
643         return std::make_pair (name, width);
644 }
645
646 Gtk::Label *
647 Gtkmm2ext::left_aligned_label (string const & t)
648 {
649         Gtk::Label* l = new Gtk::Label (t);
650         l->set_alignment (0, 0.5);
651         return l;
652 }
653
654 static bool
655 make_null_tooltip (int, int, bool, const Glib::RefPtr<Gtk::Tooltip>& t)
656 {
657         t->set_tip_area (Gdk::Rectangle (0, 0, 0, 0));
658         return true;
659 }
660
661 /** Hackily arrange for the provided widget to have no tooltip,
662  *  and also to stop any other widget from providing one while
663  * the mouse is over w.
664  */
665 void
666 Gtkmm2ext::set_no_tooltip_whatsoever (Gtk::Widget& w)
667 {
668         w.property_has_tooltip() = true;
669         w.signal_query_tooltip().connect (sigc::ptr_fun (make_null_tooltip));
670 }
671
672 void
673 Gtkmm2ext::enable_tooltips ()
674 {
675         gtk_rc_parse_string ("gtk-enable-tooltips = 1");
676 }
677
678 void
679 Gtkmm2ext::disable_tooltips ()
680 {
681         gtk_rc_parse_string ("gtk-enable-tooltips = 0");
682 }
683
684 const char*
685 Gtkmm2ext::event_type_string (int event_type)
686 {
687         switch (event_type) {
688         case GDK_NOTHING:
689                 return "nothing";
690         case GDK_DELETE:
691                 return "delete";
692         case GDK_DESTROY:
693                 return "destroy";
694         case GDK_EXPOSE:
695                 return "expose";
696         case GDK_MOTION_NOTIFY:
697                 return "motion_notify";
698         case GDK_BUTTON_PRESS:
699                 return "button_press";
700         case GDK_2BUTTON_PRESS:
701                 return "2button_press";
702         case GDK_3BUTTON_PRESS:
703                 return "3button_press";
704         case GDK_BUTTON_RELEASE:
705                 return "button_release";
706         case GDK_KEY_PRESS:
707                 return "key_press";
708         case GDK_KEY_RELEASE:
709                 return "key_release";
710         case GDK_ENTER_NOTIFY:
711                 return "enter_notify";
712         case GDK_LEAVE_NOTIFY:
713                 return "leave_notify";
714         case GDK_FOCUS_CHANGE:
715                 return "focus_change";
716         case GDK_CONFIGURE:
717                 return "configure";
718         case GDK_MAP:
719                 return "map";
720         case GDK_UNMAP:
721                 return "unmap";
722         case GDK_PROPERTY_NOTIFY:
723                 return "property_notify";
724         case GDK_SELECTION_CLEAR:
725                 return "selection_clear";
726         case GDK_SELECTION_REQUEST:
727                 return "selection_request";
728         case GDK_SELECTION_NOTIFY:
729                 return "selection_notify";
730         case GDK_PROXIMITY_IN:
731                 return "proximity_in";
732         case GDK_PROXIMITY_OUT:
733                 return "proximity_out";
734         case GDK_DRAG_ENTER:
735                 return "drag_enter";
736         case GDK_DRAG_LEAVE:
737                 return "drag_leave";
738         case GDK_DRAG_MOTION:
739                 return "drag_motion";
740         case GDK_DRAG_STATUS:
741                 return "drag_status";
742         case GDK_DROP_START:
743                 return "drop_start";
744         case GDK_DROP_FINISHED:
745                 return "drop_finished";
746         case GDK_CLIENT_EVENT:
747                 return "client_event";
748         case GDK_VISIBILITY_NOTIFY:
749                 return "visibility_notify";
750         case GDK_NO_EXPOSE:
751                 return "no_expose";
752         case GDK_SCROLL:
753                 return "scroll";
754         case GDK_WINDOW_STATE:
755                 return "window_state";
756         case GDK_SETTING:
757                 return "setting";
758         case GDK_OWNER_CHANGE:
759                 return "owner_change";
760         case GDK_GRAB_BROKEN:
761                 return "grab_broken";
762         case GDK_DAMAGE:
763                 return "damage";
764         }
765
766         return "unknown";
767 }