/* * this file was largely taken from the oxygen gtk engine * Copyright (c) 2010 Hugo Pereira Da Costa * Copyright (c) 2010 Ruslan Kabatsayev * * GdkPixbuf modification code from Walmis * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or( at your option ) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "tdegtk-utils.h" //#include "oxygengtktypenames.h" #include "config.h" #include #include #include #include #include //_____________________________________________________________________________ std::ostream& operator << ( std::ostream& out, const GtkWidgetPath* path ) { if( !path ) { out << " (null)"; } else { for( gint pos=0; pos0 && y>0 && x < allocation.width && y < allocation.height) && gtk_widget_get_state(button)==GTK_STATE_ACTIVE ) { gtk_widget_set_state(button,GTK_STATE_NORMAL); } gtk_button_set_relief(GTK_BUTTON(button),GTK_RELIEF_NORMAL); gtk_widget_set_size_request(button,16,16); return; } if(GTK_IS_CONTAINER(container)) { gtk_container_foreach(container,(GtkCallback)gtk_container_adjust_buttons_state,0L); } } //____________________________________________________________ bool Gtk::gtk_widget_path_has_type( const GtkWidgetPath* path, GType type ) { if( !path ) return false; for( gint pos=0; posdata ); if( children ) g_list_free( children ); return result; } //________________________________________________________ GtkWidget* Gtk::gtk_button_find_image(GtkWidget* button) { // check widget type if(!GTK_IS_CONTAINER(button)) return 0L; GtkWidget* result( 0L ); GList* children( gtk_container_get_children( GTK_CONTAINER( button ) ) ); for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) { if( GTK_IS_IMAGE( child->data ) ) { result = GTK_WIDGET( child->data ); break; } else if( GTK_IS_CONTAINER( child->data ) ) { result = gtk_button_find_image( GTK_WIDGET(child->data ) ); break; } } if( children ) g_list_free( children ); return result; } //________________________________________________________ GtkWidget* Gtk::gtk_button_find_label(GtkWidget* button) { // check widget type if( !GTK_IS_CONTAINER(button) ) return 0L; GtkWidget* result( 0L ); GList* children( gtk_container_get_children( GTK_CONTAINER( button ) ) ); for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) { if( GTK_IS_LABEL( child->data) ) { result = GTK_WIDGET( child->data ); break; } else if( GTK_IS_CONTAINER( child->data ) ) { result = gtk_button_find_image(GTK_WIDGET(child->data)); break; } } if( children ) g_list_free( children ); return result; } //________________________________________________________ bool Gtk::gtk_combobox_has_frame( GtkWidget* widget ) { GValue val = { 0, }; g_value_init(&val, G_TYPE_BOOLEAN); g_object_get_property( G_OBJECT( widget ), "has-frame", &val ); return (bool) g_value_get_boolean( &val ); } //________________________________________________________ bool Gtk::gtk_combobox_is_tree_view( GtkWidget* widget ) { // check types and path if( !widget && GTK_IS_TREE_VIEW( widget ) && GTK_IS_SCROLLED_WINDOW( gtk_widget_get_parent( widget ) ) ) return false; return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window.GtkScrolledWindow.GtkTreeView"; } //________________________________________________________ bool Gtk::gtk_combobox_is_scrolled_window( GtkWidget* widget ) { // check types and path if( !GTK_IS_SCROLLED_WINDOW(widget) ) return false; return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window.GtkScrolledWindow"; } //________________________________________________________ bool Gtk::gtk_combobox_is_viewport( GtkWidget* widget ) { if( !GTK_IS_VIEWPORT(widget) ) return false; static const std::string match( "gtk-combo-popup-window" ); return Gtk::gtk_widget_path( widget ).substr( 0, match.size() ) == match; } //________________________________________________________ bool Gtk::gtk_combobox_is_frame( GtkWidget* widget ) { if( !GTK_IS_FRAME(widget) ) return false; static const std::string match( "gtk-combo-popup-window" ); return Gtk::gtk_widget_path( widget ).substr( 0, match.size() ) == match; } //________________________________________________________ bool Gtk::gtk_combobox_appears_as_list( GtkWidget* widget ) { gboolean appearsAsList; gtk_widget_style_get( widget, "appears-as-list", &appearsAsList, NULL ); return (bool) appearsAsList; } //________________________________________________________ bool Gtk::gtk_notebook_tab_contains( GtkWidget* widget, int tab, int x, int y ) { if( !( tab >= 0 && GTK_IS_NOTEBOOK( widget ) ) ) return false; // cast to notebook and check against number of pages GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); if( tab >= gtk_notebook_get_n_pages( notebook ) ) return false; // retrieve page and tab label GtkWidget* page( gtk_notebook_get_nth_page( notebook, tab ) ); GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); // get allocted size and compare to position const GtkAllocation allocation( gtk_widget_get_allocation( tabLabel ) ); return Gtk::gdk_rectangle_contains( &allocation, x, y ); } //________________________________________________________ int Gtk::gtk_notebook_find_tab( GtkWidget* widget, int x, int y ) { if( !GTK_IS_NOTEBOOK( widget ) ) return -1; // cast to notebook and check against number of pages GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); int tab(-1); int minDistance( -1 ); for( int i = gtk_notebook_find_first_tab( widget ); i < gtk_notebook_get_n_pages( notebook ); ++i ) { // retrieve page and tab label GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); if( !page ) continue; // get label GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); if(!tabLabel) continue; // get allocted size and compare to position const GtkAllocation allocation( gtk_widget_get_allocation( tabLabel ) ); // get manhattan length const int distance = int( std::abs( double( allocation.x + allocation.width/2 - x ) ) + std::abs( double( allocation.y + allocation.height/2 - y ) ) ); if( minDistance < 0 || distance < minDistance ) { tab = i; minDistance = distance; } } return tab; } //________________________________________________________ int Gtk::gtk_notebook_find_first_tab( GtkWidget* widget ) { // TODO: reimplement with gtk+3.0 return 0; // if( !GTK_IS_NOTEBOOK( widget ) ) return 0; // // // cast to notebook // GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); // return g_list_position( notebook->children, notebook->first_tab ); } //____________________________________________________________ bool Gtk::gtk_notebook_is_tab_label(GtkNotebook* notebook, GtkWidget* widget ) { for( int i = 0; i < gtk_notebook_get_n_pages( notebook ); ++i ) { // retrieve page and tab label GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); if( !page ) continue; GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); if( widget == tabLabel ) return true; } return false; } //____________________________________________________________ void Gtk::gtk_notebook_get_tabbar_rect( GtkNotebook* notebook, GdkRectangle* rect ) { // check notebook and rect if( !( notebook && rect ) ) return; // check tab visibility GList* children( gtk_container_get_children( GTK_CONTAINER( notebook ) ) ); if( !( gtk_notebook_get_show_tabs( notebook ) && children ) ) { if( children ) g_list_free( children ); *rect = gdk_rectangle(); return; } // free children if( children ) g_list_free( children ); // get full rect gtk_widget_get_allocation( GTK_WIDGET( notebook ), rect ); // adjust to account for borderwidth guint borderWidth( gtk_container_get_border_width( GTK_CONTAINER( notebook ) ) ); rect->x += borderWidth; rect->y += borderWidth; rect->height -= 2*borderWidth; rect->width -= 2*borderWidth; // get current page int pageIndex( gtk_notebook_get_current_page( notebook ) ); if( !( pageIndex >= 0 && pageIndex < gtk_notebook_get_n_pages( notebook ) ) ) { *rect = gdk_rectangle(); return; } GtkWidget* page( gtk_notebook_get_nth_page( notebook, pageIndex ) ); if( !page ) { *rect = gdk_rectangle(); return; } // removes page allocated size from rect, based on tabwidget orientation const GtkAllocation pageAllocation( gtk_widget_get_allocation( page ) ); switch( gtk_notebook_get_tab_pos( notebook ) ) { case GTK_POS_BOTTOM: rect->y += pageAllocation.height; rect->height -= pageAllocation.height; break; case GTK_POS_TOP: rect->height -= pageAllocation.height; break; case GTK_POS_RIGHT: rect->x += pageAllocation.width; rect->width -= pageAllocation.width; break; case GTK_POS_LEFT: rect->width -= pageAllocation.width; break; } return; } //____________________________________________________________ bool Gtk::gtk_notebook_has_visible_arrows( GtkNotebook* notebook ) { if( !gtk_notebook_get_show_tabs( notebook ) ) return false; // loop over pages for( int i = 0; i < gtk_notebook_get_n_pages( notebook ); ++i ) { // retrieve page and tab label GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); if( !page ) continue; GtkWidget* label( gtk_notebook_get_tab_label( notebook, page ) ); if( label && !gtk_widget_get_mapped( label ) ) return true; } return false; } //____________________________________________________________ bool Gtk::gtk_notebook_update_close_buttons(GtkNotebook* notebook) { int numPages=gtk_notebook_get_n_pages( notebook ); for( int i = 0; i < numPages; ++i ) { // retrieve page GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); if( !page ) continue; // retrieve tab label GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); if( tabLabel && GTK_IS_CONTAINER( tabLabel ) ) { gtk_container_adjust_buttons_state( GTK_CONTAINER( tabLabel ) ); } } return FALSE; } //________________________________________________________ bool Gtk::gtk_notebook_is_close_button(GtkWidget* widget) { if( GtkNotebook* nb=GTK_NOTEBOOK(gtk_parent_notebook(widget) ) ) { // check if the button resides on tab label, not anywhere on the tab bool tabLabelIsParent=false; for( int i=0; i < gtk_notebook_get_n_pages(nb); ++i ) { GtkWidget* tabLabel( gtk_notebook_get_tab_label(nb,gtk_notebook_get_nth_page( nb, i ) ) ); if( gtk_widget_is_parent( widget, GTK_WIDGET(tabLabel) ) ) { tabLabelIsParent=true; } } if( !tabLabelIsParent ) return false; // make sure button has no text and some image (for now, just hope it's a close icon) if( gtk_button_find_image(widget) && !gtk_button_get_label( GTK_BUTTON(widget) ) ) { return true; } // check for pidgin 'x' close button if( GtkWidget* label = gtk_button_find_label(widget) ) { const gchar* labelText=gtk_label_get_text( GTK_LABEL(label) ); if(!strcmp(labelText,"×")) // It's not letter 'x' - it's a special symbol { gtk_widget_hide( label ); return true; } else return false; } else return false; } else return false; } //________________________________________________________ bool Gtk::gtk_scrolled_window_force_sunken( GtkWidget* widget) { // FMIconView (from nautilus) always get sunken if( g_object_is_a( G_OBJECT( widget ), "FMIconView" ) ) return true; // other checks require widget to be of type GtkBin if( !GTK_IS_BIN( widget ) ) return false; // retrieve child GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) ); if( GTK_IS_TREE_VIEW( child ) || GTK_IS_ICON_VIEW( child ) ) return true; else return false; } //________________________________________________________ bool Gtk::gdk_window_map_to_toplevel( GdkWindow* window, gint* x, gint* y, gint* w, gint* h, bool frame ) { // always initialize arguments (to invalid values) if( x ) *x=0; if( y ) *y=0; if( w ) *w = -1; if( h ) *h = -1; if( !( window && GDK_IS_WINDOW( window ) ) ) return false; if( gdk_window_get_window_type( window ) == GDK_WINDOW_OFFSCREEN ) return false; // get window size and height if( frame ) gdk_toplevel_get_frame_size( window, w, h ); else gdk_toplevel_get_size( window, w, h ); Gtk::gdk_window_get_toplevel_origin( window, x, y ); return ((!w) || *w > 0) && ((!h) || *h>0); } //________________________________________________________ bool Gtk::gtk_widget_map_to_toplevel( GtkWidget* widget, gint* x, gint* y, gint* w, gint* h, bool frame ) { // always initialize arguments (to invalid values) if( x ) *x=0; if( y ) *y=0; if( w ) *w = -1; if( h ) *h = -1; if( !widget ) return false; // get window GdkWindow* window( gtk_widget_get_parent_window( widget ) ); if( !( window && GDK_IS_WINDOW( window ) ) ) return false; if( gdk_window_get_window_type( window ) == GDK_WINDOW_OFFSCREEN ) return false; if( frame ) gdk_toplevel_get_frame_size( window, w, h ); else gdk_toplevel_get_size( window, w, h ); int xlocal, ylocal; const bool success( gtk_widget_translate_coordinates( widget, gtk_widget_get_toplevel( widget ), 0, 0, &xlocal, &ylocal ) ); if( success ) { if( x ) *x=xlocal; if( y ) *y=ylocal; } return success && ((!w) || *w > 0) && ((!h) || *h>0); } //________________________________________________________ bool Gtk::gtk_widget_map_to_parent( GtkWidget* widget, GtkWidget* parent, gint* x, gint* y, gint* w, gint* h ) { // always initialize arguments (to invalid values) if( x ) *x=0; if( y ) *y=0; if( w ) *w = -1; if( h ) *h = -1; if( !( widget && parent ) ) return false; const GtkAllocation allocation( gtk_widget_get_allocation( parent ) ); if( w ) *w = allocation.width; if( h ) *h = allocation.height; int xlocal, ylocal; const bool success( gtk_widget_translate_coordinates( widget, parent, 0, 0, &xlocal, &ylocal ) ); if( success ) { if( x ) *x=xlocal; if( y ) *y=ylocal; } return success && ((!w) || *w > 0) && ((!h) || *h>0); } //________________________________________________________ bool Gtk::gdk_window_translate_origin( GdkWindow* parent, GdkWindow* child, gint* x, gint* y ) { if( x ) *x = 0; if( y ) *y = 0; if( !( parent && child ) ) return false; while( child && GDK_IS_WINDOW( child ) && child != parent && gdk_window_get_window_type( child ) == GDK_WINDOW_CHILD ) { gint xloc; gint yloc; gdk_window_get_position( child, &xloc, &yloc ); if( x ) *x += xloc; if( y ) *y += yloc; child = gdk_window_get_parent( child ); } return( child == parent ); } //________________________________________________________ void Gtk::gdk_toplevel_get_size( GdkWindow* window, gint* w, gint* h ) { if( !( window && GDK_IS_WINDOW( window ) ) ) { if( w ) *w = -1; if( h ) *h = -1; return; } if( GdkWindow* topLevel = gdk_window_get_toplevel( window ) ) { if( w ) *w = gdk_window_get_width( topLevel ); if( h ) *h = gdk_window_get_height( topLevel ); } else { if( w ) *w = gdk_window_get_width( window ); if( h ) *h = gdk_window_get_height( window ); } return; } //________________________________________________________ void Gtk::gdk_toplevel_get_frame_size( GdkWindow* window, gint* w, gint* h ) { if( !( window && GDK_IS_WINDOW( window ) ) ) { if( w ) *w = -1; if( h ) *h = -1; return; } GdkWindow* topLevel = gdk_window_get_toplevel( window ); if( topLevel && GDK_IS_WINDOW( topLevel ) ) { if( gdk_window_get_window_type( topLevel ) == GDK_WINDOW_OFFSCREEN ) { if( w ) *w = gdk_window_get_width(topLevel); if( h ) *h = gdk_window_get_height(topLevel); } else { GdkRectangle rect = {0, 0, -1, -1}; gdk_window_get_frame_extents( topLevel, &rect ); if( w ) *w = rect.width; if( h ) *h = rect.height; } } return; } //________________________________________________________ void Gtk::gdk_window_get_toplevel_origin( GdkWindow* window, gint* x, gint* y ) { if( x ) *x = 0; if( y ) *y = 0; if( !window ) return; while( window && GDK_IS_WINDOW( window ) && gdk_window_get_window_type( window ) == GDK_WINDOW_CHILD ) { gint xloc; gint yloc; gdk_window_get_position( window, &xloc, &yloc ); if( x ) *x += xloc; if( y ) *y += yloc; window = gdk_window_get_parent( window ); } return; } //___________________________________________________________ GdkPixbuf* Gtk::gdk_pixbuf_set_alpha( const GdkPixbuf *pixbuf, double alpha ) { g_return_val_if_fail( pixbuf != 0L, 0L); g_return_val_if_fail( GDK_IS_PIXBUF( pixbuf ), 0L ); /* Returns a copy of pixbuf with it's non-completely-transparent pixels to have an alpha level "alpha" of their original value. */ GdkPixbuf* target( gdk_pixbuf_add_alpha( pixbuf, false, 0, 0, 0 ) ); if( alpha >= 1.0 ) return target; if( alpha < 0 ) alpha = 0; const int width( gdk_pixbuf_get_width( target ) ); const int height( gdk_pixbuf_get_height( target ) ); const int rowstride( gdk_pixbuf_get_rowstride( target ) ); unsigned char* data = gdk_pixbuf_get_pixels( target ); for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { /* The "4" is the number of chars per pixel, in this case, RGBA, the 3 means "skip to the alpha" */ unsigned char* current = data + ( y*rowstride ) + ( x*4 ) + 3; *(current) = (unsigned char) ( *( current )*alpha ); } } return target; } //_________________________________________________________ bool Gtk::gdk_pixbuf_to_gamma(GdkPixbuf* pixbuf, double value) { if(gdk_pixbuf_get_colorspace(pixbuf)==GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(pixbuf)==8 && gdk_pixbuf_get_has_alpha(pixbuf) && gdk_pixbuf_get_n_channels(pixbuf)==4) { double gamma=1./(2.*value+0.5); unsigned char* data=gdk_pixbuf_get_pixels(pixbuf); const int height=gdk_pixbuf_get_height(pixbuf); const int width=gdk_pixbuf_get_width(pixbuf); const int rowstride=gdk_pixbuf_get_rowstride(pixbuf); for(int x=0;x(g_object_ref (src)); } else { return gdk_pixbuf_scale_simple( src, width, height, GDK_INTERP_BILINEAR ); } } //___________________________________________________________ void Gtk::gtk_viewport_get_position( GtkViewport* viewport, gint* x, gint* y ) { // initialize if( x ) *x = 0; if( y ) *y = 0; // get windows and derive offsets gint xBin(0), yBin(0); gdk_window_get_geometry( gtk_viewport_get_bin_window( viewport ), &xBin, &yBin, 0, 0 ); gint xView(0), yView(0); gdk_window_get_geometry( gtk_viewport_get_view_window( viewport ), &xView, &yView, 0, 0 ); // calculate offsets if( x ) *x = xView - xBin; if( y ) *y = yView - yBin; // also correct from widget thickness GtkStyle* style( gtk_widget_get_style( GTK_WIDGET( viewport ) ) ); if( style ) { if( x ) *x -= style->xthickness; if( y ) *y -= style->ythickness; } return; } //___________________________________________________________ GtkWidget* Gtk::gtk_dialog_find_button(GtkDialog* dialog,gint response_id) { // get children of dialog's action area GList* children( gtk_container_get_children( GTK_CONTAINER( gtk_dialog_get_action_area( dialog ) ) ) ); #if OXYGEN_DEBUG std::cerr << "Oxygen::Gtk::gtk_dialog_find_button - buttons: "; #endif for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) { // check data if( !GTK_IS_WIDGET( child->data ) ) continue; GtkWidget* childWidget( GTK_WIDGET( child->data ) ); const gint id( gtk_dialog_get_response_for_widget(dialog, childWidget ) ); #if OXYGEN_DEBUG std::cerr << Gtk::TypeNames::response( (GtkResponseType) id ) << ", "; #endif if( id == response_id ) return childWidget; } #if OXYGEN_DEBUG std::cerr << std::endl; #endif if( children ) g_list_free( children ); return 0L; }