File indexing completed on 2024-04-28 05:32:12

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004     SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
0005 
0006     GdkPixbuf modification code from Walmis
0007     <http://gnome-look.org/content/show.php?content=77783&forumpage=3>
0008 
0009     SPDX-License-Identifier: LGPL-2.0-or-later
0010 */
0011 
0012 #include "oxygengtkutils.h"
0013 #include "oxygengtktypenames.h"
0014 #include "config.h"
0015 
0016 #include <cmath>
0017 #include <cstring>
0018 #include <gtk/gtk.h>
0019 #include <iostream>
0020 #include <set>
0021 
0022 namespace Oxygen
0023 {
0024     GQuark Gtk::Quarks::_rcStyle = 0L;
0025 
0026     //____________________________________________________________
0027     void Gtk::gtk_container_adjust_buttons_state(GtkContainer* container,gpointer data)
0028     {
0029         if(GTK_IS_BUTTON(container))
0030         {
0031             int x,y;
0032             GtkWidget* button=GTK_WIDGET(container);
0033             GtkAllocation allocation( gtk_widget_get_allocation( button ) );
0034             gtk_widget_get_pointer(button,&x,&y);
0035             if( !(x>0 && y>0 &&
0036                 x < allocation.width &&
0037                 y < allocation.height) && gtk_widget_get_state(button)==GTK_STATE_ACTIVE )
0038             { gtk_widget_set_state(button,GTK_STATE_NORMAL); }
0039 
0040             gtk_button_set_relief(GTK_BUTTON(button),GTK_RELIEF_NORMAL);
0041             gtk_widget_set_size_request(button,16,16);
0042 
0043             return;
0044 
0045         }
0046 
0047         if(GTK_IS_CONTAINER(container))
0048         { gtk_container_foreach(container,(GtkCallback)gtk_container_adjust_buttons_state,0L); }
0049 
0050     }
0051 
0052     //____________________________________________________________
0053     bool Gtk::gtk_widget_has_custom_background( GtkWidget* widget, GtkStateType state )
0054     {
0055 
0056         // loop over all parents, recursively
0057         for( GtkWidget* parent = widget; parent; parent = gtk_widget_get_parent( parent ) )
0058         { if( gtk_widget_get_modifier_style(parent)->color_flags[state]&GTK_RC_BG ) return true; }
0059 
0060         return false;
0061 
0062     }
0063 
0064     //____________________________________________________________
0065     bool Gtk::gtk_widget_is_applet( GtkWidget* widget )
0066     {
0067         if( !widget ) return false;
0068 
0069         #if OXYGEN_DEBUG
0070         std::cerr << "Gtk::gtk_widget_is_applet(): " << Gtk::gtk_widget_path(widget) << std::endl;
0071         #endif
0072 
0073         static const char* names[] =
0074         {
0075             "Panel",
0076             "PanelWidget",
0077             "PanelApplet",
0078             "XfcePanelWindow",
0079             0
0080         };
0081 
0082         // check widget name
0083         std::string name( G_OBJECT_TYPE_NAME( widget ) );
0084         for( unsigned int i = 0; names[i]; ++i )
0085         { if( g_object_is_a( G_OBJECT( widget ), names[i] ) || name.find( names[i] ) == 0  ) return true; }
0086 
0087         // also check parent
0088         if( GtkWidget* parent = gtk_widget_get_parent( widget ) )
0089         {
0090             name = G_OBJECT_TYPE_NAME( parent );
0091             for( unsigned int i = 0; names[i]; ++i )
0092             { if( g_object_is_a( G_OBJECT( parent ), names[i] ) || name.find( names[i] ) == 0 ) return true; }
0093 
0094         }
0095 
0096         // also check first widget path element (needed for xfce panel)
0097         std::string widgetPath=Gtk::gtk_widget_path(widget);
0098         {
0099             for( unsigned int i = 0; names[i]; ++i )
0100             {
0101                 if( widgetPath.find(names[i]) != std::string::npos )
0102                     return true;
0103             }
0104         }
0105 
0106         return false;
0107 
0108     }
0109 
0110     //____________________________________________________________
0111     void Gtk::gtk_widget_print_tree( GtkWidget* widget )
0112     {
0113 
0114         if( !widget ) return;
0115         std::cerr << "Oxygen::Gtk::gtk_widget_print_tree - widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl;
0116         while( ( widget = gtk_widget_get_parent( widget ) ) )
0117         { std::cerr << "    parent: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; }
0118 
0119     }
0120 
0121     //________________________________________________________
0122     bool Gtk::gdk_default_screen_is_composited( void )
0123     {
0124         GdkScreen* screen( gdk_screen_get_default() );
0125         return (screen && gdk_screen_is_composited( screen ) );
0126     }
0127 
0128     //________________________________________________________
0129     bool Gtk::gtk_widget_has_rgba( GtkWidget* widget )
0130     {
0131 
0132         if( !widget ) return false;
0133         if( !gdk_default_screen_is_composited() ) return false;
0134         return gdk_visual_has_rgba( gtk_widget_get_visual (widget) );
0135 
0136     }
0137 
0138     //________________________________________________________
0139     bool Gtk::gdk_window_is_base( GdkWindow* window )
0140     {
0141 
0142         if( !GDK_IS_WINDOW( window ) ) return false;
0143 
0144         GdkWindowTypeHint hint = gdk_window_get_type_hint( window );
0145 
0146         #if OXYGEN_DEBUG
0147         std::cerr << "Gtk::gdk_window_is_base - " << TypeNames::windowTypeHint( hint ) << std::endl;
0148         #endif
0149 
0150         return(
0151             hint == GDK_WINDOW_TYPE_HINT_NORMAL ||
0152             hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
0153             hint == GDK_WINDOW_TYPE_HINT_UTILITY );
0154     }
0155 
0156     //________________________________________________________
0157     bool Gtk::gdk_window_nobackground( GdkWindow* window )
0158     {
0159         if( !GDK_IS_WINDOW( window ) ) return false;
0160 
0161         GdkWindowTypeHint hint = gdk_window_get_type_hint( window );
0162         return( hint == GDK_WINDOW_TYPE_HINT_COMBO || hint == GDK_WINDOW_TYPE_HINT_TOOLTIP );
0163 
0164     }
0165 
0166     //________________________________________________________
0167     bool Gtk::gdk_window_has_rgba( GdkWindow* window )
0168     {
0169 
0170         if( !window ) return false;
0171 
0172         if( !gdk_default_screen_is_composited() ) return false;
0173         return gdk_visual_has_rgba( gdk_drawable_get_visual( GDK_DRAWABLE( window ) ) );
0174 
0175     }
0176 
0177     //________________________________________________________
0178     bool Gtk::gdk_visual_has_rgba( GdkVisual* visual )
0179     {
0180         return
0181             visual->depth == 32 &&
0182             visual->red_mask   == 0xff0000 &&
0183             visual->green_mask == 0x00ff00 &&
0184             visual->blue_mask  == 0x0000ff;
0185 
0186     }
0187 
0188     //________________________________________________________
0189     bool Gtk::g_object_is_a( const GObject* object, const std::string& typeName )
0190     {
0191 
0192         if( object )
0193         {
0194             const GType tmp( g_type_from_name( typeName.c_str() ) );
0195             if( tmp )
0196             { return g_type_check_instance_is_a( (GTypeInstance*) object, tmp ); }
0197         }
0198 
0199         return false;
0200     }
0201 
0202     //________________________________________________________
0203     std::string Gtk::gtk_widget_path( GtkWidget* widget )
0204     {
0205 
0206         if(GTK_IS_WIDGET(widget))
0207         {
0208             gchar* widgetPath;
0209             gtk_widget_path( widget, 0L, &widgetPath, 0L);
0210             const std::string  out( widgetPath );
0211             g_free( widgetPath );
0212             return out;
0213         }
0214         return std::string("not-widget");
0215 
0216     }
0217 
0218     //________________________________________________________
0219     GtkWidget* Gtk::gtk_widget_find_parent( GtkWidget* widget, GType type )
0220     {
0221 
0222         for( GtkWidget* parent = widget; parent; parent = gtk_widget_get_parent( parent ) )
0223         { if( G_TYPE_CHECK_INSTANCE_TYPE( parent, type ) ) return parent; }
0224 
0225         return 0L;
0226     }
0227 
0228     //________________________________________________________
0229     GtkWidget* Gtk::gtk_parent_groupbox( GtkWidget* widget )
0230     {
0231 
0232         for( GtkWidget* parent = widget; parent; parent = gtk_widget_get_parent( parent ) )
0233         { if( gtk_widget_is_groupbox( parent ) ) return parent; }
0234 
0235         return 0L;
0236     }
0237 
0238     //________________________________________________________
0239     bool Gtk::gtk_widget_is_parent( GtkWidget* widget, GtkWidget* potentialParent )
0240     {
0241 
0242         for( GtkWidget* parent = gtk_widget_get_parent( widget ); parent; parent = gtk_widget_get_parent( parent ) )
0243         { if( potentialParent==parent ) return true; }
0244 
0245         return false;
0246     }
0247 
0248     //________________________________________________________
0249     bool Gtk::gtk_parent_is_shadow_in( GtkWidget* widget )
0250     {
0251         for( GtkWidget* parent = gtk_widget_get_parent( widget ); parent; parent = gtk_widget_get_parent( parent ) )
0252         {
0253             if( GTK_IS_FRAME( parent ) && gtk_frame_get_shadow_type( GTK_FRAME( parent ) ) == GTK_SHADOW_IN ) return true;
0254             if( GTK_IS_SCROLLED_WINDOW( parent ) && gtk_scrolled_window_get_shadow_type( GTK_SCROLLED_WINDOW( parent ) ) == GTK_SHADOW_IN ) return true;
0255         }
0256 
0257         return false;
0258     }
0259 
0260     //________________________________________________________
0261     bool Gtk::gtk_button_is_flat( GtkWidget* widget )
0262     {
0263         if( !GTK_IS_BUTTON( widget ) ) return false;
0264         return ( gtk_button_get_relief( GTK_BUTTON( widget ) ) == GTK_RELIEF_NONE );
0265     }
0266 
0267     //________________________________________________________
0268     bool Gtk::gtk_button_is_header( GtkWidget* widget )
0269     {
0270         if( !GTK_IS_BUTTON( widget ) ) return false;
0271         return gtk_parent_tree_view( widget ) || gtk_widget_find_parent( widget, "GimpThumbBox" );
0272     }
0273 
0274     //________________________________________________________
0275     bool Gtk::gtk_button_is_in_path_bar( GtkWidget* widget )
0276     {
0277         if( !( GTK_IS_BUTTON( widget ) && gtk_widget_get_parent( widget ) ) ) return false;
0278 
0279         std::string name(G_OBJECT_TYPE_NAME( gtk_widget_get_parent( widget ) ) );
0280         return name == "GtkPathBar" || name == "NautilusPathBar";
0281     }
0282 
0283     //________________________________________________________
0284     bool Gtk::gtk_path_bar_button_is_last( GtkWidget* widget )
0285     {
0286 
0287         GtkWidget* parent( gtk_widget_get_parent( widget ) );
0288 
0289         // get parent and check type
0290         if( !( parent && GTK_IS_CONTAINER( parent ) ) ) return false;
0291 
0292         // get children
0293         GList* children( gtk_container_get_children( GTK_CONTAINER( parent ) ) );
0294 
0295         /*
0296         for some reason, pathbar buttons are ordered in the container in reverse order.
0297         meaning that the last button (in the pathbar) is stored first in the list.
0298         */
0299         bool result = (widget == g_list_first( children )->data );
0300         if( children ) g_list_free( children );
0301         return result;
0302 
0303     }
0304 
0305     //________________________________________________________
0306     GtkWidget* Gtk::gtk_button_find_image(GtkWidget* button)
0307     {
0308 
0309         // check widget type
0310         if(!GTK_IS_CONTAINER(button)) return 0L;
0311 
0312         GtkWidget* result( 0L );
0313         GList* children( gtk_container_get_children( GTK_CONTAINER( button ) ) );
0314         for( GList *child = g_list_first( children ); child; child = g_list_next( child ) )
0315         {
0316             if( GTK_IS_IMAGE( child->data ) )
0317             {
0318                 result = GTK_WIDGET( child->data );
0319                 break;
0320 
0321             } else if( GTK_IS_CONTAINER( child->data ) ) {
0322 
0323                 result = gtk_button_find_image( GTK_WIDGET(child->data ) );
0324                 break;
0325 
0326             }
0327 
0328         }
0329 
0330         if( children ) g_list_free( children );
0331         return result;
0332 
0333     }
0334 
0335     //________________________________________________________
0336     GtkWidget* Gtk::gtk_button_find_label(GtkWidget* button)
0337     {
0338 
0339         // check widget type
0340         if( !GTK_IS_CONTAINER(button) ) return 0L;
0341 
0342         GtkWidget* result( 0L );
0343         GList* children( gtk_container_get_children( GTK_CONTAINER( button ) ) );
0344         for( GList *child = g_list_first( children ); child; child = g_list_next( child ) )
0345         {
0346 
0347             if( GTK_IS_LABEL( child->data) )
0348             {
0349                 result = GTK_WIDGET( child->data );
0350                 break;
0351 
0352             } else if( GTK_IS_CONTAINER( child->data ) ) {
0353 
0354                 result = gtk_button_find_image(GTK_WIDGET(child->data));
0355                 break;
0356 
0357             }
0358 
0359         }
0360 
0361         if( children ) g_list_free( children );
0362         return result;
0363 
0364     }
0365 
0366     //________________________________________________________
0367     bool Gtk::gtk_combobox_has_frame( GtkWidget* widget )
0368     {
0369 
0370         GValue val = { 0, };
0371         g_value_init(&val, G_TYPE_BOOLEAN);
0372         g_object_get_property( G_OBJECT( widget ), "has-frame", &val );
0373         return (bool) g_value_get_boolean( &val );
0374 
0375     }
0376 
0377     //________________________________________________________
0378     bool Gtk::gtk_combobox_is_tree_view( GtkWidget* widget )
0379     {
0380         // check types and path
0381         if( !widget && GTK_IS_TREE_VIEW( widget ) && GTK_IS_SCROLLED_WINDOW( gtk_widget_get_parent( widget ) ) ) return false;
0382         return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window.GtkScrolledWindow.GtkTreeView";
0383     }
0384 
0385     //________________________________________________________
0386     bool Gtk::gtk_combobox_is_scrolled_window( GtkWidget* widget )
0387     {
0388         // check types and path
0389         if( !GTK_IS_SCROLLED_WINDOW(widget) ) return false;
0390         return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window.GtkScrolledWindow";
0391     }
0392 
0393     //________________________________________________________
0394     bool Gtk::gtk_combobox_is_popup( GtkWidget* widget )
0395     {
0396         // check types and path
0397         if( !GTK_IS_WINDOW(widget) ) return false;
0398         return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window";
0399     }
0400 
0401     //________________________________________________________
0402     bool Gtk::gtk_combo_is_viewport( GtkWidget* widget )
0403     {
0404         if( !GTK_IS_VIEWPORT(widget) ) return false;
0405         static const std::string match( "gtk-combo-popup-window" );
0406         return Gtk::gtk_widget_path( widget ).substr( 0, match.size() ) == match;
0407     }
0408 
0409     //________________________________________________________
0410     bool Gtk::gtk_combo_is_frame( GtkWidget* widget )
0411     {
0412         if( !GTK_IS_FRAME(widget) ) return false;
0413         static const std::string match( "gtk-combo-popup-window" );
0414         return Gtk::gtk_widget_path( widget ).substr( 0, match.size() ) == match;
0415     }
0416 
0417     //________________________________________________________
0418     bool Gtk::gtk_combo_is_popup( GtkWidget* widget )
0419     {
0420         if( !GTK_IS_WINDOW(widget) ) return false;
0421         static const std::string match( "gtk-combo-popup-window" );
0422         return Gtk::gtk_widget_path( widget ) == match;
0423     }
0424 
0425     //________________________________________________________
0426     bool Gtk::gtk_combobox_appears_as_list( GtkWidget* widget )
0427     {
0428         gboolean appearsAsList;
0429         gtk_widget_style_get( widget, "appears-as-list", &appearsAsList, NULL );
0430         return (bool) appearsAsList;
0431     }
0432 
0433     //________________________________________________________
0434     bool Gtk::gtk_is_tooltip( GtkWidget* widget )
0435     {
0436         if( GTK_IS_TOOLTIP(widget) ) return true;
0437         const std::string path(Gtk::gtk_widget_path( widget ));
0438         return  path == "gtk-tooltip" || path == "gtk-tooltips";
0439     }
0440 
0441     //________________________________________________________
0442     bool Gtk::gtk_notebook_tab_contains( GtkWidget* widget, int tab, int x, int y )
0443     {
0444 
0445         if( !( tab >= 0 && GTK_IS_NOTEBOOK( widget ) ) ) return false;
0446 
0447         // cast to notebook and check against number of pages
0448         GtkNotebook* notebook( GTK_NOTEBOOK( widget ) );
0449         if( tab >= gtk_notebook_get_n_pages( notebook ) ) return false;
0450 
0451         // retrieve page and tab label
0452         GtkWidget* page( gtk_notebook_get_nth_page( notebook, tab ) );
0453         GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) );
0454 
0455         // get allocted size and compare to position
0456         const GtkAllocation allocation( gtk_widget_get_allocation( tabLabel ) );
0457         return Gtk::gdk_rectangle_contains( &allocation, x, y );
0458 
0459     }
0460 
0461      //________________________________________________________
0462     int Gtk::gtk_notebook_find_tab( GtkWidget* widget, int x, int y )
0463     {
0464 
0465         if( !GTK_IS_NOTEBOOK( widget ) ) return -1;
0466 
0467         // cast to notebook and check against number of pages
0468         GtkNotebook* notebook( GTK_NOTEBOOK( widget ) );
0469         int tab(-1);
0470         int minDistance( -1 );
0471         for( int i = gtk_notebook_find_first_tab( widget ); i <  gtk_notebook_get_n_pages( notebook ); ++i )
0472         {
0473 
0474             // retrieve page and tab label
0475             GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) );
0476             if( !page ) continue;
0477 
0478             // get label
0479             GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) );
0480             if(!tabLabel) continue;
0481 
0482             // get allocted size and compare to position
0483             const GtkAllocation allocation( gtk_widget_get_allocation( tabLabel ) );
0484 
0485             // get manhattan length
0486             const int distance = int(
0487                 std::abs( double( allocation.x + allocation.width/2 - x ) ) +
0488                 std::abs( double( allocation.y + allocation.height/2 - y ) ) );
0489             if( minDistance < 0 || distance < minDistance )
0490             {
0491                 tab = i;
0492                 minDistance = distance;
0493             }
0494         }
0495 
0496         return tab;
0497 
0498     }
0499 
0500     //________________________________________________________
0501     int Gtk::gtk_notebook_find_first_tab( GtkWidget* widget )
0502     {
0503 
0504         if( !GTK_IS_NOTEBOOK( widget ) ) return 0;
0505 
0506         // cast to notebook
0507         GtkNotebook* notebook( GTK_NOTEBOOK( widget ) );
0508         return g_list_position( notebook->children, notebook->first_tab );
0509 
0510     }
0511 
0512     //____________________________________________________________
0513     bool Gtk::gtk_notebook_is_tab_label(GtkNotebook* notebook, GtkWidget* widget )
0514     {
0515 
0516         for( int i = 0; i <  gtk_notebook_get_n_pages( notebook ); ++i )
0517         {
0518             // retrieve page and tab label
0519             GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) );
0520             if( !page ) continue;
0521 
0522             GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) );
0523             if( widget == tabLabel ) return true;
0524         }
0525 
0526         return false;
0527 
0528     }
0529 
0530 
0531     //____________________________________________________________
0532     void Gtk::gtk_notebook_get_tabbar_rect( GtkNotebook* notebook, GdkRectangle* rect )
0533     {
0534         // check notebook and rect
0535         if( !( notebook && rect ) ) return;
0536 
0537         // check tab visibility
0538         GList* children( gtk_container_get_children( GTK_CONTAINER( notebook ) ) );
0539         if( !( gtk_notebook_get_show_tabs( notebook ) && children ) )
0540         {
0541             if( children ) g_list_free( children );
0542             *rect = gdk_rectangle();
0543             return;
0544         }
0545 
0546         // free children
0547         if( children ) g_list_free( children );
0548 
0549         // get full rect
0550         gtk_widget_get_allocation( GTK_WIDGET( notebook ), rect );
0551 
0552         // adjust to account for borderwidth
0553         guint borderWidth( gtk_container_get_border_width( GTK_CONTAINER( notebook ) ) );
0554         rect->x += borderWidth;
0555         rect->y += borderWidth;
0556         rect->height -= 2*borderWidth;
0557         rect->width -= 2*borderWidth;
0558 
0559         // get current page
0560         int pageIndex( gtk_notebook_get_current_page( notebook ) );
0561         if( !( pageIndex >= 0 && pageIndex < gtk_notebook_get_n_pages( notebook ) ) )
0562         {
0563             *rect = gdk_rectangle();
0564             return;
0565         }
0566 
0567         GtkWidget* page( gtk_notebook_get_nth_page( notebook, pageIndex ) );
0568         if( !page )
0569         {
0570             *rect = gdk_rectangle();
0571             return;
0572         }
0573 
0574         // removes page allocated size from rect, based on tabwidget orientation
0575         const GtkAllocation pageAllocation( gtk_widget_get_allocation( page ) );
0576         switch( gtk_notebook_get_tab_pos( notebook ) )
0577         {
0578             case GTK_POS_BOTTOM:
0579             rect->height += rect->y - (pageAllocation.y + pageAllocation.height);
0580             rect->y = pageAllocation.y + pageAllocation.height;
0581             break;
0582 
0583             case GTK_POS_TOP:
0584             rect->height = pageAllocation.y - rect->y;
0585             break;
0586 
0587             case GTK_POS_RIGHT:
0588             rect->width += rect->x - (pageAllocation.x + pageAllocation.width);
0589             rect->x = pageAllocation.x + pageAllocation.width;
0590             break;
0591 
0592             case GTK_POS_LEFT:
0593             rect->width = pageAllocation.x - rect->x;
0594             break;
0595         }
0596 
0597         return;
0598 
0599     }
0600 
0601     //____________________________________________________________
0602     bool Gtk::gtk_notebook_has_visible_arrows( GtkNotebook* notebook )
0603     {
0604 
0605         if( !gtk_notebook_get_show_tabs( notebook ) ) return false;
0606 
0607         // loop over pages
0608         for( int i = 0; i <  gtk_notebook_get_n_pages( notebook ); ++i )
0609         {
0610 
0611             // retrieve page and tab label
0612             GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) );
0613             if( !page ) continue;
0614 
0615             GtkWidget* label( gtk_notebook_get_tab_label( notebook, page ) );
0616 
0617             #if GTK_CHECK_VERSION(2, 20, 0)
0618             if( label && !gtk_widget_get_mapped( label ) ) return true;
0619             #else
0620             if( label && !GTK_WIDGET_MAPPED( label ) ) return true;
0621             #endif
0622         }
0623 
0624         return false;
0625 
0626     }
0627 
0628     //____________________________________________________________
0629     bool Gtk::gtk_notebook_update_close_buttons(GtkNotebook* notebook)
0630     {
0631         int numPages=gtk_notebook_get_n_pages( notebook );
0632         for( int i = 0; i < numPages; ++i )
0633         {
0634 
0635             // retrieve page
0636             GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) );
0637             if( !page ) continue;
0638 
0639             // retrieve tab label
0640             GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) );
0641             if( tabLabel && GTK_IS_CONTAINER( tabLabel ) )
0642             { gtk_container_adjust_buttons_state( GTK_CONTAINER( tabLabel ) ); }
0643 
0644         }
0645         return FALSE;
0646     }
0647 
0648     //________________________________________________________
0649     bool Gtk::gtk_notebook_is_close_button(GtkWidget* widget)
0650     {
0651         if( GtkNotebook* nb=GTK_NOTEBOOK(gtk_parent_notebook(widget) ) )
0652         {
0653             // check if the button resides on tab label, not anywhere on the tab
0654             bool tabLabelIsParent=false;
0655             for( int i=0; i < gtk_notebook_get_n_pages(nb); ++i )
0656             {
0657                 GtkWidget* tabLabel( gtk_notebook_get_tab_label(nb,gtk_notebook_get_nth_page( nb, i ) ) );
0658                 if( gtk_widget_is_parent( widget, GTK_WIDGET(tabLabel) ) )
0659                 { tabLabelIsParent=true; }
0660             }
0661 
0662             if( !tabLabelIsParent ) return false;
0663 
0664             // make sure button has no text and some image (for now, just hope it's a close icon)
0665             if( gtk_button_find_image(widget) && !gtk_button_get_label( GTK_BUTTON(widget) ) )
0666             { return true; }
0667 
0668             // check for pidgin 'x' close button
0669             if( GtkWidget* label = gtk_button_find_label(widget) )
0670             {
0671 
0672                 const gchar* labelText=gtk_label_get_text( GTK_LABEL(label) );
0673                 if(!strcmp(labelText,"×")) // It's not letter 'x' - it's a special symbol
0674                 {
0675                     gtk_widget_hide( label );
0676                     return true;
0677                 } else return false;
0678 
0679             } else return false;
0680 
0681         } else return false;
0682 
0683     }
0684 
0685     //________________________________________________________
0686     bool Gtk::gtk_scrolled_window_force_sunken( GtkWidget* widget)
0687     {
0688 
0689         // FMIconView (from nautilus) always get sunken
0690         if( g_object_is_a( G_OBJECT( widget ), "FMIconView" ) ) return true;
0691 
0692         // other checks require widget to be of type GtkBin
0693         if( !GTK_IS_BIN( widget ) ) return false;
0694 
0695         // retrieve child
0696         GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
0697         if( GTK_IS_TREE_VIEW( child ) || GTK_IS_ICON_VIEW( child ) ) return true;
0698         else return false;
0699 
0700     }
0701 
0702     //________________________________________________________
0703     bool Gtk::gdk_window_map_to_toplevel( GdkWindow* window, gint* x, gint* y, gint* w, gint* h, bool frame )
0704     {
0705 
0706         // always initialize arguments (to invalid values)
0707         if( x ) *x=0;
0708         if( y ) *y=0;
0709         if( w ) *w = -1;
0710         if( h ) *h = -1;
0711 
0712         if( !( window && GDK_IS_WINDOW( window ) ) ) return false;
0713 
0714         // get window size and height
0715         if( frame ) gdk_toplevel_get_frame_size( window, w, h );
0716         else gdk_toplevel_get_size( window, w, h );
0717         Gtk::gdk_window_get_toplevel_origin( window, x, y );
0718         return ((!w) || *w > 0) && ((!h) || *h>0);
0719 
0720     }
0721 
0722     //________________________________________________________
0723     bool Gtk::gtk_widget_map_to_toplevel( GtkWidget* widget, gint* x, gint* y, gint* w, gint* h, bool frame )
0724     {
0725 
0726         // always initialize arguments (to invalid values)
0727         if( x ) *x=0;
0728         if( y ) *y=0;
0729         if( w ) *w = -1;
0730         if( h ) *h = -1;
0731 
0732         if( !widget ) return false;
0733 
0734         // get window
0735         GdkWindow* window( gtk_widget_get_parent_window( widget ) );
0736         if( !( window && GDK_IS_WINDOW( window ) ) ) return false;
0737 
0738         if( frame ) gdk_toplevel_get_frame_size( window, w, h );
0739         else gdk_toplevel_get_size( window, w, h );
0740         int xlocal, ylocal;
0741         const bool success( gtk_widget_translate_coordinates( widget, gtk_widget_get_toplevel( widget ), 0, 0, &xlocal, &ylocal ) );
0742         if( success )
0743         {
0744 
0745             if( x ) *x=xlocal;
0746             if( y ) *y=ylocal;
0747 
0748         }
0749 
0750         return success && ((!w) || *w > 0) && ((!h) || *h>0);
0751 
0752     }
0753 
0754     //________________________________________________________
0755     bool Gtk::gtk_widget_map_to_parent( GtkWidget* widget, GtkWidget* parent, gint* x, gint* y, gint* w, gint* h )
0756     {
0757 
0758         // always initialize arguments (to invalid values)
0759         if( x ) *x=0;
0760         if( y ) *y=0;
0761         if( w ) *w = -1;
0762         if( h ) *h = -1;
0763 
0764         if( !( widget && parent ) ) return false;
0765 
0766         const GtkAllocation allocation( gtk_widget_get_allocation(  parent ) );
0767         if( w ) *w = allocation.width;
0768         if( h ) *h = allocation.height;
0769 
0770         int xlocal, ylocal;
0771         const bool success( gtk_widget_translate_coordinates( widget, parent, 0, 0, &xlocal, &ylocal ) );
0772         if( success )
0773         {
0774 
0775             if( x ) *x=xlocal;
0776             if( y ) *y=ylocal;
0777 
0778         }
0779 
0780         return success && ((!w) || *w > 0) && ((!h) || *h>0);
0781 
0782     }
0783 
0784     //________________________________________________________
0785     bool Gtk::gdk_window_translate_origin( GdkWindow* parent, GdkWindow* child, gint* x, gint* y )
0786     {
0787         if( x ) *x = 0;
0788         if( y ) *y = 0;
0789         if( !( parent && child ) ) return false;
0790         while( child && GDK_IS_WINDOW( child ) &&
0791             child != parent &&
0792             gdk_window_get_window_type( child ) == GDK_WINDOW_CHILD )
0793         {
0794             gint xloc;
0795             gint yloc;
0796             gdk_window_get_position( child, &xloc, &yloc );
0797             if( x ) *x += xloc;
0798             if( y ) *y += yloc;
0799             child = gdk_window_get_parent( child );
0800         }
0801 
0802         return( child == parent );
0803 
0804     }
0805 
0806     //________________________________________________________
0807     void Gtk::gdk_toplevel_get_size( GdkWindow* window, gint* w, gint* h )
0808     {
0809 
0810         if( !( window && GDK_IS_WINDOW( window ) ) )
0811         {
0812             if( w ) *w = -1;
0813             if( h ) *h = -1;
0814             return;
0815         }
0816 
0817         if( GdkWindow* topLevel = gdk_window_get_toplevel( window ) )
0818         {
0819             gdk_drawable_get_size( topLevel, w, h );
0820         } else gdk_drawable_get_size( window, w, h );
0821 
0822         return;
0823 
0824     }
0825 
0826     //________________________________________________________
0827     void Gtk::gdk_toplevel_get_frame_size( GdkWindow* window, gint* w, gint* h )
0828     {
0829 
0830         if( !( window && GDK_IS_WINDOW( window ) ) )
0831         {
0832             if( w ) *w = -1;
0833             if( h ) *h = -1;
0834             return;
0835         }
0836 
0837         if( GdkWindow* topLevel = gdk_window_get_toplevel( window ) )
0838         {
0839             GdkRectangle rect = {0, 0, -1, -1};
0840             gdk_window_get_frame_extents( topLevel, &rect );
0841             if( w ) *w = rect.width;
0842             if( h ) *h = rect.height;
0843         }
0844 
0845         return;
0846 
0847     }
0848 
0849     //________________________________________________________
0850     void Gtk::gdk_window_get_toplevel_origin( GdkWindow* window, gint* x, gint* y )
0851     {
0852         if( x ) *x = 0;
0853         if( y ) *y = 0;
0854         if( !window ) return;
0855         while( window && GDK_IS_WINDOW( window ) && gdk_window_get_window_type( window ) == GDK_WINDOW_CHILD )
0856         {
0857             gint xloc;
0858             gint yloc;
0859             gdk_window_get_position( window, &xloc, &yloc );
0860             if( x ) *x += xloc;
0861             if( y ) *y += yloc;
0862             window = gdk_window_get_parent( window );
0863         }
0864 
0865         return;
0866     }
0867 
0868     //___________________________________________________________
0869     GdkPixbuf* Gtk::gdk_pixbuf_set_alpha( const GdkPixbuf *pixbuf, double alpha )
0870     {
0871 
0872         g_return_val_if_fail( pixbuf != 0L, 0L);
0873         g_return_val_if_fail( GDK_IS_PIXBUF( pixbuf ), 0L );
0874 
0875         /* Returns a copy of pixbuf with it's non-completely-transparent pixels to
0876         have an alpha level "alpha" of their original value. */
0877         GdkPixbuf* target( gdk_pixbuf_add_alpha( pixbuf, false, 0, 0, 0 ) );
0878         if( alpha >= 1.0 ) return target;
0879         if( alpha < 0 ) alpha = 0;
0880 
0881         const int width( gdk_pixbuf_get_width( target ) );
0882         const int height( gdk_pixbuf_get_height( target ) );
0883         const int rowstride( gdk_pixbuf_get_rowstride( target ) );
0884         unsigned char* data = gdk_pixbuf_get_pixels( target );
0885 
0886         for( int y = 0; y < height; ++y )
0887         {
0888 
0889             for( int x = 0; x < width; ++x )
0890             {
0891                 /* The "4" is the number of chars per pixel, in this case, RGBA,
0892                 the 3 means "skip to the alpha" */
0893                 unsigned char* current = data + ( y*rowstride ) + ( x*4 ) + 3;
0894                 *(current) = (unsigned char) ( *( current )*alpha );
0895             }
0896         }
0897 
0898         return target;
0899     }
0900 
0901     //_________________________________________________________
0902     bool Gtk::gdk_pixbuf_to_gamma(GdkPixbuf* pixbuf, double value)
0903     {
0904         if(gdk_pixbuf_get_colorspace(pixbuf)==GDK_COLORSPACE_RGB &&
0905             gdk_pixbuf_get_bits_per_sample(pixbuf)==8 &&
0906             gdk_pixbuf_get_has_alpha(pixbuf) &&
0907             gdk_pixbuf_get_n_channels(pixbuf)==4)
0908         {
0909             double gamma=1./(2.*value+0.5);
0910             unsigned char* data=gdk_pixbuf_get_pixels(pixbuf);
0911             const int height=gdk_pixbuf_get_height(pixbuf);
0912             const int width=gdk_pixbuf_get_width(pixbuf);
0913             const int rowstride=gdk_pixbuf_get_rowstride(pixbuf);
0914             for(int x=0;x<width;++x)
0915             {
0916                 for(int y=0; y<height; y++)
0917                 {
0918                     unsigned char* p=data + y*rowstride + x*4;
0919                     *p=(char)(pow((*p/255.),gamma)*255); ++p;
0920                     *p=(char)(pow((*p/255.),gamma)*255); ++p;
0921                     *p=(char)(pow((*p/255.),gamma)*255);
0922                 }
0923 
0924             }
0925 
0926             return true;
0927 
0928         } else return false;
0929 
0930     }
0931 
0932     //___________________________________________________________
0933     GdkPixbuf* Gtk::gdk_pixbuf_resize( GdkPixbuf* src, int width, int height )
0934     {
0935         if( width == gdk_pixbuf_get_width( src ) &&  height == gdk_pixbuf_get_height( src ) )
0936         {
0937 
0938             return static_cast<GdkPixbuf*>(g_object_ref (src));
0939 
0940         } else {
0941 
0942             return gdk_pixbuf_scale_simple( src, width, height, GDK_INTERP_BILINEAR );
0943 
0944         }
0945 
0946     }
0947 
0948     //___________________________________________________________
0949     void Gtk::gtk_viewport_get_position( GtkViewport* viewport, gint* x, gint* y )
0950     {
0951 
0952         // initialize
0953         if( x ) *x = 0;
0954         if( y ) *y = 0;
0955 
0956         // get bin window
0957         #if GTK_CHECK_VERSION( 2, 20, 0 )
0958         GdkWindow* binWindow( gtk_viewport_get_bin_window( viewport ) );
0959         #else
0960         GdkWindow* binWindow( viewport->bin_window );
0961         #endif
0962 
0963         gint xBin(0), yBin(0);
0964         gdk_window_get_geometry( binWindow, &xBin, &yBin, 0, 0, 0 );
0965 
0966         // get view window
0967         #if GTK_CHECK_VERSION( 2, 22, 0 )
0968         GdkWindow* viewWindow( gtk_viewport_get_view_window( viewport ) );
0969         #else
0970         GdkWindow* viewWindow( viewport->view_window );
0971         #endif
0972 
0973         gint xView(0), yView(0);
0974         gdk_window_get_geometry( viewWindow, &xView, &yView, 0, 0, 0 );
0975 
0976         // calculate offsets
0977         if( x ) *x = xView - xBin;
0978         if( y ) *y = yView - yBin;
0979 
0980         // also correct from widget thickness
0981         GtkStyle* style( gtk_widget_get_style( GTK_WIDGET( viewport ) ) );
0982         if( style )
0983         {
0984             if( x ) *x -= style->xthickness;
0985             if( y ) *y -= style->ythickness;
0986         }
0987 
0988         return;
0989 
0990     }
0991 
0992     //___________________________________________________________
0993     GtkWidget* Gtk::gtk_dialog_find_button(GtkDialog* dialog,gint response_id)
0994     {
0995 
0996         // get children of dialog's action area
0997         GList* children( gtk_container_get_children( GTK_CONTAINER( gtk_dialog_get_action_area( dialog ) ) ) );
0998 
0999         #if OXYGEN_DEBUG
1000         std::cerr << "Oxygen::Gtk::gtk_dialog_find_button - buttons: ";
1001         #endif
1002 
1003         for( GList *child = g_list_first( children ); child; child = g_list_next( child ) )
1004         {
1005 
1006             // check data
1007             if( !GTK_IS_WIDGET( child->data ) ) continue;
1008             GtkWidget* childWidget( GTK_WIDGET( child->data ) );
1009 
1010             const gint id( gtk_dialog_get_response_for_widget(dialog, childWidget ) );
1011 
1012             #if OXYGEN_DEBUG
1013             std::cerr << Gtk::TypeNames::response( (GtkResponseType) id ) << ", ";
1014             #endif
1015             if( id == response_id ) return childWidget;
1016 
1017         }
1018 
1019         #if OXYGEN_DEBUG
1020         std::cerr << std::endl;
1021         #endif
1022 
1023         if( children ) g_list_free( children );
1024         return 0L;
1025 
1026     }
1027 
1028 
1029 }