File indexing completed on 2024-05-12 17:05:50
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 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "oxygenscrolledwindowdata.h" 0010 #include "../oxygengtkutils.h" 0011 #include "../config.h" 0012 #include "../oxygencairocontext.h" 0013 #include "oxygenanimations.h" 0014 0015 #include <cassert> 0016 #include <iostream> 0017 0018 namespace Oxygen 0019 { 0020 0021 //_____________________________________________ 0022 void ScrolledWindowData::connect( GtkWidget* widget ) 0023 { 0024 assert( GTK_IS_SCROLLED_WINDOW( widget ) ); 0025 assert( !_target ); 0026 0027 // store target 0028 _target = widget; 0029 0030 // register scrollbars 0031 GtkScrolledWindow* scrolledWindow( GTK_SCROLLED_WINDOW( widget ) ); 0032 0033 if( GtkWidget* hScrollBar = gtk_scrolled_window_get_hscrollbar( scrolledWindow ) ) 0034 { registerChild( hScrollBar ); } 0035 0036 if( GtkWidget* vScrollBar = gtk_scrolled_window_get_vscrollbar( scrolledWindow ) ) 0037 { registerChild( vScrollBar ); } 0038 0039 // check child 0040 GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) ); 0041 if( !child ) return; 0042 0043 #if OXYGEN_DEBUG 0044 std::cerr 0045 << "Oxygen::ScrolledWindowData::connect -" 0046 << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")" 0047 << std::endl; 0048 #endif 0049 0050 if( GTK_IS_TREE_VIEW( child ) || GTK_IS_TEXT_VIEW( child ) || GTK_IS_ICON_VIEW( child ) ) 0051 { 0052 0053 registerChild( child ); 0054 0055 } else { 0056 0057 // list widget types for which scrolled window needs register 0058 static const char* widgetTypes[] = { "ExoIconView", "FMIconContainer", 0L }; 0059 for( unsigned int i = 0; widgetTypes[i]; i++ ) 0060 { 0061 if( Gtk::g_object_is_a( G_OBJECT( child ), widgetTypes[i] ) ) 0062 { 0063 registerChild( child ); 0064 break; 0065 } 0066 } 0067 0068 } 0069 0070 } 0071 0072 //_____________________________________________ 0073 void ScrolledWindowData::disconnect( GtkWidget* ) 0074 { 0075 _target = 0; 0076 for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter ) 0077 { iter->second.disconnect( iter->first ); } 0078 0079 _childrenData.clear(); 0080 } 0081 0082 //________________________________________________________________________________ 0083 void ScrolledWindowData::setHovered( GtkWidget* widget, bool value ) 0084 { 0085 0086 bool oldHover( hovered() ); 0087 ChildDataMap::iterator iter( _childrenData.find( widget ) ); 0088 if( iter != _childrenData.end() ) iter->second._hovered = value; 0089 else return; 0090 0091 // need to schedule repaint of the whole widget 0092 if( oldHover != hovered() && _target ) gtk_widget_queue_draw( _target ); 0093 0094 } 0095 0096 //________________________________________________________________________________ 0097 void ScrolledWindowData::setFocused( GtkWidget* widget, bool value ) 0098 { 0099 0100 bool oldFocus( focused() ); 0101 ChildDataMap::iterator iter( _childrenData.find( widget ) ); 0102 if( iter != _childrenData.end() ) iter->second._focused = value; 0103 else return; 0104 0105 // need to schedule repaint of the whole widget 0106 if( oldFocus != focused() && _target ) gtk_widget_queue_draw( _target ); 0107 0108 } 0109 0110 //_____________________________________________ 0111 void ScrolledWindowData::registerChild( GtkWidget* widget ) 0112 { 0113 // make sure widget is not already in map 0114 if( _childrenData.find( widget ) == _childrenData.end() ) 0115 { 0116 0117 #if OXYGEN_DEBUG 0118 std::cerr 0119 << "Oxygen::ScrolledWindowData::registerChild -" 0120 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0121 << std::endl; 0122 #endif 0123 0124 // adjust event mask 0125 gtk_widget_add_events( widget, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK ); 0126 0127 // allocate new Hover data 0128 ChildData data; 0129 data._destroyId.connect( G_OBJECT(widget), "destroy", G_CALLBACK( childDestroyNotifyEvent ), this ); 0130 data._enterId.connect( G_OBJECT(widget), "enter-notify-event", G_CALLBACK( enterNotifyEvent ), this ); 0131 data._leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( leaveNotifyEvent ), this ); 0132 data._focusInId.connect( G_OBJECT(widget), "focus-in-event", G_CALLBACK( focusInNotifyEvent ), this ); 0133 data._focusOutId.connect( G_OBJECT(widget), "focus-out-event", G_CALLBACK( focusOutNotifyEvent ), this ); 0134 0135 // and insert in map 0136 _childrenData.insert( std::make_pair( widget, data ) ); 0137 0138 // set initial focus 0139 setFocused( widget, gtk_widget_has_focus( widget ) ); 0140 0141 // set initial hover 0142 const bool enabled( gtk_widget_get_state( widget ) != GTK_STATE_INSENSITIVE ); 0143 0144 // on connection, needs to check whether mouse pointer is in widget or not 0145 // to have the proper initial value of the hover flag 0146 if( enabled && gtk_widget_get_window( widget ) ) 0147 { 0148 0149 gint xPointer,yPointer; 0150 gdk_window_get_pointer( gtk_widget_get_window( widget ), &xPointer, &yPointer, 0L ); 0151 const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) ); 0152 const GdkRectangle rect( Gtk::gdk_rectangle( 0, 0, allocation.width, allocation.height ) ); 0153 setHovered( widget, Gtk::gdk_rectangle_contains( &rect, xPointer, yPointer ) ); 0154 0155 } else setHovered( widget, false ); 0156 0157 } 0158 0159 } 0160 0161 //________________________________________________________________________________ 0162 void ScrolledWindowData::unregisterChild( GtkWidget* widget ) 0163 { 0164 0165 // loopup in hover map 0166 ChildDataMap::iterator iter( _childrenData.find( widget ) ); 0167 if( iter == _childrenData.end() ) return; 0168 0169 #if OXYGEN_DEBUG 0170 std::cerr 0171 << "Oxygen::ScrolledWindowData::unregisterChild -" 0172 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0173 << std::endl; 0174 #endif 0175 0176 iter->second.disconnect( widget ); 0177 _childrenData.erase( iter ); 0178 0179 } 0180 0181 //________________________________________________________________________________ 0182 #if OXYGEN_DEBUG 0183 void ScrolledWindowData::ChildData::disconnect( GtkWidget* widget ) 0184 #else 0185 void ScrolledWindowData::ChildData::disconnect( GtkWidget* ) 0186 #endif 0187 { 0188 0189 #if OXYGEN_DEBUG 0190 std::cerr 0191 << "Oxygen::ScrolledWindowData::ChildData::disconnect -" 0192 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0193 << std::endl; 0194 #endif 0195 0196 _destroyId.disconnect(); 0197 _enterId.disconnect(); 0198 _leaveId.disconnect(); 0199 _focusInId.disconnect(); 0200 _focusOutId.disconnect(); 0201 _hovered = false; 0202 _focused = false; 0203 0204 } 0205 0206 //____________________________________________________________________________________________ 0207 gboolean ScrolledWindowData::childDestroyNotifyEvent( GtkWidget* widget, gpointer data ) 0208 { 0209 #if OXYGEN_DEBUG 0210 std::cerr 0211 << "Oxygen::ScrolledWindowData::childDestroyNotifyEvent -" 0212 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0213 << std::endl; 0214 #endif 0215 static_cast<ScrolledWindowData*>(data)->unregisterChild( widget ); 0216 return FALSE; 0217 } 0218 0219 //________________________________________________________________________________ 0220 gboolean ScrolledWindowData::enterNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data ) 0221 { 0222 0223 #if OXYGEN_DEBUG 0224 std::cerr << "Oxygen::ScrolledWindowData::enterNotifyEvent -" 0225 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0226 << std::endl; 0227 #endif 0228 0229 if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) ) 0230 { static_cast<ScrolledWindowData*>( data )->setHovered( widget, true ); } 0231 0232 return FALSE; 0233 } 0234 0235 //________________________________________________________________________________ 0236 gboolean ScrolledWindowData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data ) 0237 { 0238 0239 #if OXYGEN_DEBUG 0240 std::cerr << "Oxygen::ScrolledWindowData::leaveNotifyEvent -" 0241 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0242 << std::endl; 0243 #endif 0244 0245 if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) ) 0246 { static_cast<ScrolledWindowData*>( data )->setHovered( widget, false ); } 0247 0248 return FALSE; 0249 } 0250 0251 //________________________________________________________________________________ 0252 gboolean ScrolledWindowData::focusInNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data ) 0253 { 0254 0255 #if OXYGEN_DEBUG 0256 std::cerr << "Oxygen::ScrolledWindowData::focusInNotifyEvent -" 0257 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0258 << std::endl; 0259 #endif 0260 0261 static_cast<ScrolledWindowData*>( data )->setFocused( widget, true ); 0262 return FALSE; 0263 } 0264 0265 //________________________________________________________________________________ 0266 gboolean ScrolledWindowData::focusOutNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data ) 0267 { 0268 0269 #if OXYGEN_DEBUG 0270 std::cerr << "Oxygen::ScrolledWindowData::focusOutNotifyEvent -" 0271 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0272 << std::endl; 0273 #endif 0274 0275 static_cast<ScrolledWindowData*>( data )->setFocused( widget, false ); 0276 return FALSE; 0277 } 0278 0279 }