File indexing completed on 2024-05-12 17:05:46
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 "oxygenanimations.h" 0010 #include "../oxygengtkutils.h" 0011 #include "../oxygenqtsettings.h" 0012 #include "../config.h" 0013 0014 #include <cassert> 0015 #include <iostream> 0016 0017 namespace Oxygen 0018 { 0019 0020 //_________________________________________ 0021 Animations::Animations( void ): 0022 _innerShadowsEnabled( true ), 0023 _hooksInitialized( false ) 0024 { 0025 #if OXYGEN_DEBUG 0026 std::cerr << "Oxygen::Animations::Animations" << std::endl; 0027 #endif 0028 0029 // create engines 0030 registerEngine( _backgroundHintEngine = new BackgroundHintEngine( this ) ); 0031 registerEngine( _comboEngine = new ComboEngine( this ) ); 0032 registerEngine( _comboBoxEngine = new ComboBoxEngine( this ) ); 0033 registerEngine( _comboBoxEntryEngine = new ComboBoxEntryEngine( this ) ); 0034 registerEngine( _dialogEngine = new DialogEngine( this ) ); 0035 registerEngine( _flatWidgetEngine = new FlatWidgetEngine( this ) ); 0036 registerEngine( _groupBoxEngine = new GroupBoxEngine( this ) ); 0037 registerEngine( _groupBoxLabelEngine = new GroupBoxLabelEngine( this ) ); 0038 registerEngine( _hoverEngine = new HoverEngine( this ) ); 0039 registerEngine( _mainWindowEngine = new MainWindowEngine( this ) ); 0040 registerEngine( _menuItemEngine = new MenuItemEngine( this ) ); 0041 registerEngine( _panedEngine = new PanedEngine( this ) ); 0042 registerEngine( _scrollBarEngine = new ScrollBarEngine( this ) ); 0043 registerEngine( _scrolledWindowEngine = new ScrolledWindowEngine( this ) ); 0044 registerEngine( _innerShadowEngine = new InnerShadowEngine( this ) ); 0045 registerEngine( _tabWidgetEngine = new TabWidgetEngine( this ) ); 0046 registerEngine( _treeViewEngine = new TreeViewEngine( this ) ); 0047 registerEngine( _widgetSizeEngine = new WidgetSizeEngine( this ) ); 0048 0049 // animations specific engines 0050 registerEngine( _widgetStateEngine = new WidgetStateEngine( this ) ); 0051 registerEngine( _arrowStateEngine = new ArrowStateEngine( this ) ); 0052 registerEngine( _scrollBarStateEngine = new ScrollBarStateEngine( this ) ); 0053 registerEngine( _tabWidgetStateEngine = new TabWidgetStateEngine( this ) ); 0054 registerEngine( _treeViewStateEngine = new TreeViewStateEngine( this ) ); 0055 registerEngine( _menuBarStateEngine = new MenuBarStateEngine( this ) ); 0056 registerEngine( _menuStateEngine = new MenuStateEngine( this ) ); 0057 registerEngine( _toolBarStateEngine = new ToolBarStateEngine( this ) ); 0058 0059 } 0060 0061 //____________________________________________________________________________________________ 0062 Animations::~Animations( void ) 0063 { 0064 #if OXYGEN_DEBUG 0065 std::cerr << "Oxygen::Animations::~Animations" << std::endl; 0066 #endif 0067 0068 // delete all engines 0069 for( BaseEngine::List::iterator iter = _engines.begin(); iter != _engines.end(); ++iter ) 0070 { delete *iter; } 0071 0072 // disconnect all signals from map 0073 for( WidgetMap::iterator iter = _allWidgets.begin(); iter != _allWidgets.end(); iter++ ) 0074 { iter->second.disconnect(); } 0075 0076 // clear hooks 0077 _sizeAllocationHook.disconnect(); 0078 _realizationHook.disconnect(); 0079 _innerShadowHook.disconnect(); 0080 0081 } 0082 0083 //_________________________________________ 0084 void Animations::initialize( const QtSettings& settings ) 0085 { 0086 0087 const bool animationsEnabled( settings.animationsEnabled() ); 0088 0089 // pass animations configuration to engines 0090 _widgetStateEngine->setApplicationName( settings.applicationName() ); 0091 _widgetStateEngine->setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); 0092 _widgetStateEngine->setDuration( settings.genericAnimationsDuration() ); 0093 0094 _arrowStateEngine->setApplicationName( settings.applicationName() ); 0095 _arrowStateEngine->setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); 0096 _arrowStateEngine->setDuration( settings.genericAnimationsDuration() ); 0097 0098 _scrollBarStateEngine->setApplicationName( settings.applicationName() ); 0099 _scrollBarStateEngine->setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); 0100 _scrollBarStateEngine->setDuration( settings.genericAnimationsDuration() ); 0101 0102 _tabWidgetStateEngine->setApplicationName( settings.applicationName() ); 0103 _tabWidgetStateEngine->setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); 0104 _tabWidgetStateEngine->setDuration( settings.genericAnimationsDuration() ); 0105 0106 _treeViewStateEngine->setApplicationName( settings.applicationName() ); 0107 _treeViewStateEngine->setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); 0108 _treeViewStateEngine->setDuration( settings.genericAnimationsDuration() ); 0109 0110 _menuBarStateEngine->setApplicationName( settings.applicationName() ); 0111 _menuBarStateEngine->setAnimationsEnabled( animationsEnabled && (settings.menuBarAnimationType() != NoAnimation) ); 0112 _menuBarStateEngine->setFollowMouse( settings.menuBarAnimationType() == FollowMouse ); 0113 _menuBarStateEngine->setDuration( settings.menuBarAnimationsDuration() ); 0114 _menuBarStateEngine->setFollowMouseAnimationsDuration( settings.menuBarFollowMouseAnimationsDuration() ); 0115 0116 _menuStateEngine->setApplicationName( settings.applicationName() ); 0117 _menuStateEngine->setEnabled( animationsEnabled && (settings.menuAnimationType() != NoAnimation) ); 0118 _menuStateEngine->setFollowMouse( settings.menuAnimationType() == FollowMouse ); 0119 _menuStateEngine->setDuration( settings.menuAnimationsDuration() ); 0120 _menuStateEngine->setFollowMouseAnimationsDuration( settings.menuFollowMouseAnimationsDuration() ); 0121 0122 // for now, only Fade animations mode is supported for toolbar animations 0123 _toolBarStateEngine->setApplicationName( settings.applicationName() ); 0124 _toolBarStateEngine->setEnabled( animationsEnabled && (settings.toolBarAnimationType() != NoAnimation) ); 0125 _toolBarStateEngine->setFollowMouse( settings.toolBarAnimationType() == FollowMouse ); 0126 _toolBarStateEngine->setDuration( settings.genericAnimationsDuration() ); 0127 _toolBarStateEngine->setFollowMouseAnimationsDuration( settings.toolBarAnimationsDuration() ); 0128 0129 // background hint engine 0130 _backgroundHintEngine->setUseBackgroundGradient( settings.useBackgroundGradient() ); 0131 0132 } 0133 0134 //____________________________________________________________________________________________ 0135 void Animations::initializeHooks( void ) 0136 { 0137 if( _hooksInitialized ) return; 0138 0139 // https://bugzilla.gnome.org/show_bug.cgi?id=643416 0140 #if ENABLE_INNER_SHADOWS_HACK 0141 if(!getenv("OXYGEN_DISABLE_INNER_SHADOWS_HACK")) 0142 { _innerShadowHook.connect( "realize", (GSignalEmissionHook)innerShadowHook, this ); } 0143 #endif 0144 0145 _sizeAllocationHook.connect( "size-allocate", (GSignalEmissionHook)sizeAllocationHook, this ); 0146 _realizationHook.connect( "realize", (GSignalEmissionHook)realizationHook, this ); 0147 0148 _hooksInitialized = true; 0149 } 0150 0151 //____________________________________________________________________________________________ 0152 bool Animations::registerWidget( GtkWidget* widget ) 0153 { 0154 0155 if( _allWidgets.find( widget ) != _allWidgets.end() ) return false; 0156 0157 #if OXYGEN_DEBUG 0158 std::cerr << "Oxygen::Animations::registerWidget - " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")" << std::endl; 0159 #endif 0160 0161 Signal destroyId; 0162 destroyId.connect( G_OBJECT( widget ), "destroy", G_CALLBACK( destroyNotifyEvent ), this ); 0163 _allWidgets.insert( std::make_pair( widget, destroyId ) ); 0164 return true; 0165 0166 } 0167 0168 //____________________________________________________________________________________________ 0169 void Animations::unregisterWidget( GtkWidget* widget ) 0170 { 0171 0172 #if OXYGEN_DEBUG 0173 std::cerr << "Oxygen::Animations::unregisterWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; 0174 #endif 0175 0176 // find in map 0177 WidgetMap::iterator iter( _allWidgets.find( widget ) ); 0178 assert( iter != _allWidgets.end() ); 0179 0180 // disconnect signal 0181 iter->second.disconnect(); 0182 0183 // erase from map 0184 _allWidgets.erase( widget ); 0185 0186 // erase from all maps 0187 for( BaseEngine::List::iterator iter = _engines.begin(); iter != _engines.end(); ++iter ) 0188 { (*iter)->unregisterWidget( widget ); } 0189 0190 } 0191 0192 //____________________________________________________________________________________________ 0193 void Animations::setEnabled( bool value ) 0194 { 0195 0196 for( BaseEngine::List::iterator iter = _engines.begin(); iter != _engines.end(); ++iter ) 0197 { (*iter)->setEnabled( value ); } 0198 0199 } 0200 0201 //____________________________________________________________________________________________ 0202 gboolean Animations::destroyNotifyEvent( GtkWidget* widget, gpointer data ) 0203 { 0204 static_cast<Animations*>(data)->unregisterWidget( widget ); 0205 return FALSE; 0206 } 0207 0208 //____________________________________________________________________________________________ 0209 gboolean Animations::sizeAllocationHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) 0210 { 0211 0212 // get widget from params 0213 GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); 0214 0215 // check type 0216 if( !GTK_IS_WIDGET( widget ) ) return FALSE; 0217 0218 // cast data 0219 Animations& animations( *static_cast<Animations*>(data) ); 0220 0221 // groupbox labels 0222 #if ENABLE_GROUPBOX_HACK 0223 if( animations.groupBoxLabelEngine().contains( widget ) ) 0224 { 0225 animations.groupBoxLabelEngine().adjustSize( widget ); 0226 return TRUE; 0227 } 0228 #endif 0229 0230 #if ENABLE_COMBOBOX_LIST_RESIZE 0231 // comboboxes 0232 if( !GTK_IS_WINDOW( widget ) ) return TRUE; 0233 0234 GtkWindow* window( GTK_WINDOW( widget ) ); 0235 if( gtk_window_get_type_hint( window ) != GDK_WINDOW_TYPE_HINT_COMBO ) return TRUE; 0236 0237 GtkWidget* combobox = animations.comboBoxEngine().find( widget ); 0238 if( !combobox ) combobox = animations.comboBoxEntryEngine().find( widget ); 0239 if( !combobox ) combobox = animations.comboEngine().find( widget ); 0240 if( !combobox ) return true; 0241 0242 int w, h; 0243 gtk_window_get_size( window, &w, &h ); 0244 0245 gint targetX, dummy, y; 0246 gtk_window_get_position( window, &dummy, &y ); 0247 gdk_window_get_origin( gtk_widget_get_window( combobox ), &targetX, &dummy ); 0248 0249 const GtkAllocation comboAllocation( Gtk::gtk_widget_get_allocation( combobox ) ); 0250 int uglyShadowWidth=!Gtk::gdk_default_screen_is_composited(); 0251 gtk_window_move( window, targetX + comboAllocation.x + 3 - uglyShadowWidth, y ); 0252 0253 const GtkAllocation widgetAllocation( Gtk::gtk_widget_get_allocation( widget ) ); 0254 gtk_widget_set_size_request( widget, comboAllocation.width - 6 + 2*uglyShadowWidth, widgetAllocation.height ); 0255 #endif 0256 0257 return TRUE; 0258 0259 } 0260 0261 //____________________________________________________________________________________________ 0262 gboolean Animations::innerShadowHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) 0263 { 0264 0265 #if GTK_CHECK_VERSION(2,24,2) 0266 0267 // get widget from params 0268 GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); 0269 0270 // check type 0271 if( !GTK_IS_WIDGET( widget ) ) return FALSE; 0272 0273 // check enabled state 0274 Animations& animations( *static_cast<Animations*>(data) ); 0275 if( !animations.innerShadowsEnabled() ) return TRUE; 0276 0277 // blacklist 0278 if( Gtk::g_object_is_a( G_OBJECT( widget ), "SwtFixed" ) ) return TRUE; 0279 if( Gtk::g_object_is_a( G_OBJECT( widget ), "GtkPizza" ) ) return TRUE; 0280 0281 GtkWidget* parent(gtk_widget_get_parent(widget)); 0282 if( !GTK_IS_SCROLLED_WINDOW( parent ) ) return TRUE; 0283 0284 GtkWidget* child(gtk_bin_get_child(GTK_BIN(parent))); 0285 if(child!=widget) return TRUE; 0286 0287 #if OXYGEN_DEBUG 0288 std::cerr 0289 << "Oxygen::Animations::innerShadowHook -" 0290 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME(widget) << ")" 0291 << " parent: " << parent << " (" << G_OBJECT_TYPE_NAME(parent) << ")" 0292 << " widget path: " << Gtk::gtk_widget_path( widget ) 0293 << " isTreeView: " << (GTK_IS_TREE_VIEW(widget)?"true":"false") 0294 << " isTextView: " << (GTK_IS_TEXT_VIEW(widget)?"true":"false") 0295 << std::endl; 0296 #endif 0297 0298 // force shadow type on known windows 0299 if( Gtk::gtk_scrolled_window_force_sunken( parent ) ) 0300 { gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( parent ), GTK_SHADOW_IN ); } 0301 0302 animations.innerShadowEngine().registerWidget( parent ); 0303 animations.innerShadowEngine().registerChild( parent, widget ); 0304 0305 #endif // Gtk version 0306 return TRUE; 0307 0308 } 0309 0310 //____________________________________________________________________________________________ 0311 gboolean Animations::realizationHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) 0312 { 0313 0314 // get widget from params 0315 GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); 0316 0317 // check type 0318 if( !GTK_IS_WIDGET( widget ) ) return FALSE; 0319 0320 if( GTK_IS_NOTEBOOK( widget ) ) 0321 { gtk_notebook_set_show_border( GTK_NOTEBOOK(widget), FALSE ); } 0322 0323 #if ENABLE_GROUPBOX_HACK 0324 if( GTK_IS_LABEL( widget ) && GTK_IS_FRAME( gtk_widget_get_parent( widget ) ) ) 0325 { 0326 0327 GtkFrame *frame( GTK_FRAME( gtk_widget_get_parent( widget ) ) ); 0328 if( widget == gtk_frame_get_label_widget( frame ) && !Gtk::gtk_widget_find_parent( widget, "GtkPizza" ) ) 0329 { 0330 #if OXYGEN_DEBUG 0331 std::cout 0332 << "Oxygen::Animations::realizationHook -" 0333 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0334 << " parent: " << frame << " (" << G_OBJECT_TYPE_NAME( frame ) << ")" 0335 << std::endl; 0336 #endif 0337 0338 // modify alignment 0339 gtk_frame_set_label_align( frame, 0.5, 0.0 ); 0340 gtk_frame_set_shadow_type( frame, GTK_SHADOW_OUT ); 0341 0342 // register to engine 0343 Animations& animations( *static_cast<Animations*>(data) ); 0344 animations.groupBoxLabelEngine().registerWidget( widget ); 0345 animations.groupBoxLabelEngine().adjustSize( widget ); 0346 0347 } 0348 0349 } 0350 #endif 0351 0352 return TRUE; 0353 0354 } 0355 0356 }