1 /* 2 * this file is part of the oxygen gtk engine 3 * Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 4 * Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or(at your option ) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free 18 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 19 * MA 02110-1301, USA. 20 */ 21 22 #include "oxygenscrolledwindowdata.h" 23 #include "../oxygengtkutils.h" 24 #include "../config.h" 25 #include "../oxygencairocontext.h" 26 #include "oxygenanimations.h" 27 #include "../oxygenstyle.h" 28 29 #include <cassert> 30 #include <iostream> 31 32 namespace Oxygen 33 { 34 35 //_____________________________________________ connect(GtkWidget * widget)36 void ScrolledWindowData::connect( GtkWidget* widget ) 37 { 38 assert( GTK_IS_SCROLLED_WINDOW( widget ) ); 39 assert( !_target ); 40 41 // store target 42 _target = widget; 43 44 // register scrollbars 45 GtkScrolledWindow* scrolledWindow( GTK_SCROLLED_WINDOW( widget ) ); 46 47 if( GtkWidget* hScrollBar = gtk_scrolled_window_get_hscrollbar( scrolledWindow ) ) 48 { registerChild( hScrollBar ); } 49 50 if( GtkWidget* vScrollBar = gtk_scrolled_window_get_vscrollbar( scrolledWindow ) ) 51 { registerChild( vScrollBar ); } 52 53 // check child 54 GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) ); 55 if( !child ) return; 56 57 #if OXYGEN_DEBUG 58 std::cerr 59 << "Oxygen::ScrolledWindowData::connect -" 60 << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")" 61 << std::endl; 62 #endif 63 64 if( GTK_IS_TREE_VIEW( child ) || GTK_IS_TEXT_VIEW( child ) || GTK_IS_ICON_VIEW( child ) ) 65 { 66 67 registerChild( child ); 68 69 } else { 70 71 // list widget types for which scrolled window needs register 72 static const char* widgetTypes[] = { "ExoIconView", "FMIconContainer", 0L }; 73 for( unsigned int i = 0; widgetTypes[i]; i++ ) 74 { 75 if( Gtk::g_object_is_a( G_OBJECT( child ), widgetTypes[i] ) ) 76 { 77 registerChild( child ); 78 break; 79 } 80 } 81 82 } 83 84 } 85 86 //_____________________________________________ disconnect(GtkWidget *)87 void ScrolledWindowData::disconnect( GtkWidget* ) 88 { 89 _target = 0; 90 for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter ) 91 { iter->second.disconnect( iter->first ); } 92 93 _childrenData.clear(); 94 } 95 96 //________________________________________________________________________________ setHovered(GtkWidget * widget,bool value)97 void ScrolledWindowData::setHovered( GtkWidget* widget, bool value ) 98 { 99 100 bool oldHover( hovered() ); 101 ChildDataMap::iterator iter( _childrenData.find( widget ) ); 102 if( iter != _childrenData.end() ) iter->second._hovered = value; 103 else return; 104 105 // need to schedule repaint of the whole widget 106 if( oldHover != hovered() && _target ) gtk_widget_queue_draw( _target ); 107 108 } 109 110 //________________________________________________________________________________ setFocused(GtkWidget * widget,bool value)111 void ScrolledWindowData::setFocused( GtkWidget* widget, bool value ) 112 { 113 114 bool oldFocus( focused() ); 115 ChildDataMap::iterator iter( _childrenData.find( widget ) ); 116 if( iter != _childrenData.end() ) iter->second._focused = value; 117 else return; 118 119 // need to schedule repaint of the whole widget 120 if( oldFocus != focused() && _target ) gtk_widget_queue_draw( _target ); 121 122 } 123 124 //_____________________________________________ registerChild(GtkWidget * widget)125 void ScrolledWindowData::registerChild( GtkWidget* widget ) 126 { 127 // make sure widget is not already in map 128 if( _childrenData.find( widget ) == _childrenData.end() ) 129 { 130 131 #if OXYGEN_DEBUG 132 std::cerr 133 << "Oxygen::ScrolledWindowData::registerChild -" 134 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 135 << std::endl; 136 #endif 137 138 // adjust event mask 139 gtk_widget_add_events( widget, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK ); 140 141 // allocate new Hover data 142 ChildData data; 143 data._destroyId.connect( G_OBJECT(widget), "destroy", G_CALLBACK( childDestroyNotifyEvent ), this ); 144 data._enterId.connect( G_OBJECT(widget), "enter-notify-event", G_CALLBACK( enterNotifyEvent ), this ); 145 data._leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( leaveNotifyEvent ), this ); 146 data._focusInId.connect( G_OBJECT(widget), "focus-in-event", G_CALLBACK( focusInNotifyEvent ), this ); 147 data._focusOutId.connect( G_OBJECT(widget), "focus-out-event", G_CALLBACK( focusOutNotifyEvent ), this ); 148 149 // and insert in map 150 _childrenData.insert( std::make_pair( widget, data ) ); 151 152 // set initial focus 153 setFocused( widget, gtk_widget_has_focus( widget ) ); 154 155 // set initial hover 156 const bool enabled( gtk_widget_get_state( widget ) != GTK_STATE_INSENSITIVE ); 157 158 // on connection, needs to check whether mouse pointer is in widget or not 159 // to have the proper initial value of the hover flag 160 if( enabled && gtk_widget_get_window( widget ) ) 161 { 162 163 gint xPointer,yPointer; 164 gdk_window_get_pointer( gtk_widget_get_window( widget ), &xPointer, &yPointer, 0L ); 165 const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) ); 166 const GdkRectangle rect( Gtk::gdk_rectangle( 0, 0, allocation.width, allocation.height ) ); 167 setHovered( widget, Gtk::gdk_rectangle_contains( &rect, xPointer, yPointer ) ); 168 169 } else setHovered( widget, false ); 170 171 } 172 173 } 174 175 //________________________________________________________________________________ unregisterChild(GtkWidget * widget)176 void ScrolledWindowData::unregisterChild( GtkWidget* widget ) 177 { 178 179 // loopup in hover map 180 ChildDataMap::iterator iter( _childrenData.find( widget ) ); 181 if( iter == _childrenData.end() ) return; 182 183 #if OXYGEN_DEBUG 184 std::cerr 185 << "Oxygen::ScrolledWindowData::unregisterChild -" 186 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 187 << std::endl; 188 #endif 189 190 iter->second.disconnect( widget ); 191 _childrenData.erase( iter ); 192 193 } 194 195 //________________________________________________________________________________ 196 #if OXYGEN_DEBUG disconnect(GtkWidget * widget)197 void ScrolledWindowData::ChildData::disconnect( GtkWidget* widget ) 198 #else 199 void ScrolledWindowData::ChildData::disconnect( GtkWidget* ) 200 #endif 201 { 202 203 #if OXYGEN_DEBUG 204 std::cerr 205 << "Oxygen::ScrolledWindowData::ChildData::disconnect -" 206 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 207 << std::endl; 208 #endif 209 210 _destroyId.disconnect(); 211 _enterId.disconnect(); 212 _leaveId.disconnect(); 213 _focusInId.disconnect(); 214 _focusOutId.disconnect(); 215 _hovered = false; 216 _focused = false; 217 218 } 219 220 //____________________________________________________________________________________________ childDestroyNotifyEvent(GtkWidget * widget,gpointer data)221 gboolean ScrolledWindowData::childDestroyNotifyEvent( GtkWidget* widget, gpointer data ) 222 { 223 #if OXYGEN_DEBUG 224 std::cerr 225 << "Oxygen::ScrolledWindowData::childDestroyNotifyEvent -" 226 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 227 << std::endl; 228 #endif 229 static_cast<ScrolledWindowData*>(data)->unregisterChild( widget ); 230 return FALSE; 231 } 232 233 //________________________________________________________________________________ enterNotifyEvent(GtkWidget * widget,GdkEventCrossing * event,gpointer data)234 gboolean ScrolledWindowData::enterNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data ) 235 { 236 237 #if OXYGEN_DEBUG 238 std::cerr << "Oxygen::ScrolledWindowData::enterNotifyEvent -" 239 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 240 << std::endl; 241 #endif 242 243 if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) ) 244 { static_cast<ScrolledWindowData*>( data )->setHovered( widget, true ); } 245 246 return FALSE; 247 } 248 249 //________________________________________________________________________________ leaveNotifyEvent(GtkWidget * widget,GdkEventCrossing * event,gpointer data)250 gboolean ScrolledWindowData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data ) 251 { 252 253 #if OXYGEN_DEBUG 254 std::cerr << "Oxygen::ScrolledWindowData::leaveNotifyEvent -" 255 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 256 << std::endl; 257 #endif 258 259 if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) ) 260 { static_cast<ScrolledWindowData*>( data )->setHovered( widget, false ); } 261 262 return FALSE; 263 } 264 265 //________________________________________________________________________________ focusInNotifyEvent(GtkWidget * widget,GdkEvent *,gpointer data)266 gboolean ScrolledWindowData::focusInNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data ) 267 { 268 269 #if OXYGEN_DEBUG 270 std::cerr << "Oxygen::ScrolledWindowData::focusInNotifyEvent -" 271 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 272 << std::endl; 273 #endif 274 275 static_cast<ScrolledWindowData*>( data )->setFocused( widget, true ); 276 return FALSE; 277 } 278 279 //________________________________________________________________________________ focusOutNotifyEvent(GtkWidget * widget,GdkEvent *,gpointer data)280 gboolean ScrolledWindowData::focusOutNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data ) 281 { 282 283 #if OXYGEN_DEBUG 284 std::cerr << "Oxygen::ScrolledWindowData::focusOutNotifyEvent -" 285 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 286 << std::endl; 287 #endif 288 289 static_cast<ScrolledWindowData*>( data )->setFocused( widget, false ); 290 return FALSE; 291 } 292 293 } 294