Warning, file /plasma/oxygen-gtk/src/oxygenwindowmanager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 oxygenwindowmanager.cpp 0003 pass some window mouse press/release/move event actions to window manager 0004 ------------------- 0005 0006 SPDX-FileCopyrightText: 2010 Cédric Bellegarde <gnumdk@gmail.com> 0007 SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0008 0009 Largely inspired from Qtcurve style 0010 SPDX-FileCopyrightText: 2003-2010 Craig Drummond <craig.p.drummond@gmail.com> 0011 0012 SPDX-License-Identifier: LGPL-2.0-or-later 0013 */ 0014 0015 #include "oxygenwindowmanager.h" 0016 #include "oxygenpropertynames.h" 0017 #include "oxygenstyle.h" 0018 #include "config.h" 0019 0020 namespace Oxygen 0021 { 0022 0023 0024 //_________________________________________________ 0025 WindowManager::WindowManager( void ): 0026 _useWMMoveResize( true ), 0027 _cursorLoaded( false ), 0028 _cursor( 0L ), 0029 _oldCursor( 0L ), 0030 _dragMode( Full ), 0031 _hooksInitialized( false ), 0032 _dragAboutToStart( false ), 0033 _dragInProgress( false ), 0034 _dragDistance( 4 ), 0035 _dragDelay( 500 ), 0036 _widget( 0L ), 0037 _lastRejectedEvent( 0L ), 0038 _x(-1), 0039 _y(-1), 0040 _globalX(-1), 0041 _globalY(-1), 0042 _time(0) 0043 { 0044 #if OXYGEN_DEBUG 0045 std::cerr << "Oxygen::WindowManager::WindowManager" << std::endl; 0046 #endif 0047 0048 // black list 0049 initializeBlackList(); 0050 0051 } 0052 0053 //_________________________________________________ 0054 WindowManager::~WindowManager( void ) 0055 { 0056 0057 #if OXYGEN_DEBUG 0058 std::cerr << "Oxygen::WindowManager::~WindowManager" << std::endl; 0059 #endif 0060 0061 _styleSetHook.disconnect(); 0062 _buttonReleaseHook.disconnect(); 0063 _map.disconnectAll(); 0064 _map.clear(); 0065 0066 // cursor 0067 if( _cursor ) gdk_cursor_unref( _cursor ); 0068 0069 } 0070 0071 //_________________________________________________ 0072 void WindowManager::initializeHooks( void ) 0073 { 0074 0075 if( _hooksInitialized ) return; 0076 if( _dragMode!=Disabled ) 0077 { 0078 _styleSetHook.connect( "style-set", (GSignalEmissionHook)styleSetHook, this ); 0079 _buttonReleaseHook.connect( "button-release-event", (GSignalEmissionHook)buttonReleaseHook, this ); 0080 } 0081 _hooksInitialized = true; 0082 0083 } 0084 0085 //_________________________________________________ 0086 bool WindowManager::registerWidget( GtkWidget* widget ) 0087 { 0088 0089 // load cursor if needed 0090 if( !_cursorLoaded ) 0091 { 0092 assert( !_cursor ); 0093 GdkDisplay *display( gtk_widget_get_display( widget ) ); 0094 _cursor = gdk_cursor_new_from_name( display, "all-scroll" ); 0095 _cursorLoaded = true; 0096 } 0097 0098 if( _map.contains( widget ) ) return false; 0099 0100 // check against black listed typenames 0101 if( widgetIsBlackListed( widget ) ) 0102 { 0103 0104 #if OXYGEN_DEBUG 0105 std::cerr 0106 << "Oxygen::WindowManager::registerWidget -" 0107 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0108 << " is black listed" 0109 << std::endl; 0110 #endif 0111 0112 registerBlackListWidget( widget ); 0113 return false; 0114 } 0115 0116 // check blocking property 0117 if( g_object_get_data( G_OBJECT( widget ), PropertyNames::noWindowGrab ) ) 0118 { 0119 0120 #if OXYGEN_DEBUG 0121 std::cerr 0122 << "Oxygen::WindowManager::registerWidget -" 0123 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0124 << " requests no grab" 0125 << std::endl; 0126 #endif 0127 0128 registerBlackListWidget( widget ); 0129 return false; 0130 } 0131 0132 // Window with no decorations (set by app), let window manage it self 0133 if( GTK_IS_WINDOW( widget ) && !gtk_window_get_decorated( GTK_WINDOW( widget ) ) ) 0134 { 0135 0136 #if OXYGEN_DEBUG 0137 std::cerr 0138 << "Oxygen::WindowManager::registerWidget -" 0139 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0140 << " is not decorated" 0141 << std::endl; 0142 #endif 0143 0144 registerBlackListWidget( widget ); 0145 return false; 0146 } 0147 0148 // widgets used in tabs also must be ignored (happens, unfortunately) 0149 GtkWidget* parent( gtk_widget_get_parent( widget ) ); 0150 if( GTK_IS_NOTEBOOK( parent ) && Gtk::gtk_notebook_is_tab_label( GTK_NOTEBOOK( parent ), widget ) ) 0151 { return false; } 0152 0153 /* 0154 check event mask (for now we only need to do that for GtkWindow) 0155 The idea is that if the window has been set to receive button_press and button_release events 0156 (which is not done by default), it likely means that it does something with such events, 0157 in which case we should not use them for grabbing 0158 */ 0159 if( 0160 ( GTK_IS_WINDOW( widget ) || GTK_IS_VIEWPORT( widget ) ) && 0161 ( gtk_widget_get_events ( widget ) & 0162 ( GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK ) ) ) 0163 { 0164 #if OXYGEN_DEBUG 0165 std::cerr 0166 << "Oxygen::WindowManager::registerWidget -" 0167 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0168 << " has invalid event mask" 0169 << std::endl; 0170 #endif 0171 registerBlackListWidget( widget ); 0172 return false; 0173 } 0174 0175 // check for blacklisted parent 0176 if( widgetHasBlackListedParent( widget ) ) 0177 { 0178 0179 #if OXYGEN_DEBUG 0180 std::cerr 0181 << "Oxygen::WindowManager::registerWidget -" 0182 << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0183 << " has black listed parent" 0184 << std::endl; 0185 #endif 0186 return false; 0187 } 0188 0189 #if OXYGEN_DEBUG 0190 std::cerr 0191 << "Oxygen::WindowManager::registerWidget -" 0192 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0193 << " " << gtk_widget_get_name( widget ) 0194 << std::endl; 0195 #endif 0196 0197 // Force widget to listen to relevant events 0198 gtk_widget_add_events( widget, 0199 GDK_BUTTON_RELEASE_MASK | 0200 GDK_BUTTON_PRESS_MASK | 0201 GDK_LEAVE_NOTIFY_MASK | 0202 GDK_BUTTON1_MOTION_MASK ); 0203 0204 // allocate new Data object 0205 Data& data( _map.registerWidget( widget ) ); 0206 0207 // connect signals 0208 if( _dragMode != Disabled ) connect( widget, data ); 0209 return true; 0210 0211 } 0212 0213 //_________________________________________________ 0214 void WindowManager::unregisterWidget( GtkWidget* widget ) 0215 { 0216 if( !_map.contains( widget ) ) return; 0217 0218 #if OXYGEN_DEBUG 0219 std::cerr << "Oxygen::WindowManager::unregisterWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; 0220 #endif 0221 0222 _map.value( widget ).disconnect( widget ); 0223 _map.erase( widget ); 0224 0225 // reset drag is the current drag target 0226 if( _widget == widget ) resetDrag(); 0227 0228 } 0229 0230 //_________________________________________________ 0231 bool WindowManager::registerBlackListWidget( GtkWidget* widget ) 0232 { 0233 0234 // make sure that widget is not already connected 0235 if( _blackListWidgets.find( widget ) != _blackListWidgets.end() ) return false; 0236 0237 #if OXYGEN_DEBUG 0238 std::cerr << "Oxygen::WindowManager::registerBlackListWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; 0239 #endif 0240 0241 // connect destroy signal and insert in map 0242 Signal destroyId; 0243 destroyId.connect( G_OBJECT( widget ), "destroy", G_CALLBACK( wmBlackListDestroy ), this ); 0244 _blackListWidgets.insert( std::make_pair( widget, destroyId ) ); 0245 return true; 0246 0247 } 0248 0249 //_________________________________________________ 0250 void WindowManager::unregisterBlackListWidget( GtkWidget* widget ) 0251 { 0252 0253 WidgetMap::iterator iter( _blackListWidgets.find( widget ) ); 0254 if( iter == _blackListWidgets.end() ) return; 0255 0256 #if OXYGEN_DEBUG 0257 std::cerr << "Oxygen::WindowManager::unregisterBlackListWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; 0258 #endif 0259 0260 iter->second.disconnect(); 0261 _blackListWidgets.erase( widget ); 0262 0263 } 0264 0265 //_________________________________________________ 0266 void WindowManager::setDragMode( WindowManager::Mode mode ) 0267 { 0268 if( mode == _dragMode ) return; 0269 0270 // connect/disconnect all data in map, based on new and old mode 0271 if( mode == Disabled ) { _map.disconnectAll(); } 0272 else if( _dragMode == Disabled ) 0273 { 0274 DataMap<Data>::Map& map( _map.map() ); 0275 for( DataMap<Data>::Map::iterator iter = map.begin(); iter != map.end(); ++iter ) 0276 { connect( iter->first, iter->second ); } 0277 } 0278 0279 // assign new mode 0280 _dragMode = mode; 0281 0282 } 0283 0284 //_________________________________________________ 0285 gboolean WindowManager::wmDestroy( GtkWidget* widget, gpointer data ) 0286 { 0287 static_cast<WindowManager*>(data)->unregisterWidget( widget ); 0288 return false; 0289 } 0290 0291 //_________________________________________________ 0292 gboolean WindowManager::wmBlackListDestroy( GtkWidget* widget, gpointer data ) 0293 { 0294 static_cast<WindowManager*>(data)->unregisterBlackListWidget( widget ); 0295 return false; 0296 } 0297 0298 //_________________________________________________ 0299 gboolean WindowManager::wmButtonPress(GtkWidget *widget, GdkEventButton* event, gpointer data ) 0300 { 0301 0302 if( event->type == GDK_BUTTON_PRESS && event->button == Gtk::LeftButton ) 0303 { 0304 0305 const bool accepted( static_cast<WindowManager*>(data)->canDrag( widget, event ) ); 0306 #if OXYGEN_DEBUG 0307 std::cerr << "Oxygen::WindowManager::wmButtonPress -" 0308 << " event: " << event 0309 << " widget: " << widget 0310 << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0311 << " " << gtk_widget_get_name( widget ) 0312 << " accepted: " << accepted 0313 << std::endl; 0314 #endif 0315 0316 return accepted; 0317 0318 } else return false; 0319 0320 } 0321 0322 //_________________________________________________ 0323 gboolean WindowManager::wmLeave(GtkWidget*, GdkEventCrossing*, gpointer data ) 0324 { 0325 WindowManager& manager( *static_cast<WindowManager*>( data ) ); 0326 return (gboolean) ( manager.useWMMoveResize() && manager.resetDrag() ); 0327 } 0328 0329 //_________________________________________________ 0330 gboolean WindowManager::wmMotion( GtkWidget *widget, GdkEventMotion* event, gpointer data ) 0331 { return (gboolean) static_cast<WindowManager*>(data)->startDrag( widget, event ); } 0332 0333 //_________________________________________________________________ 0334 gboolean WindowManager::startDelayedDrag( gpointer data ) 0335 { 0336 static_cast<WindowManager*>( data )->startDrag(); 0337 return FALSE; 0338 } 0339 0340 //_________________________________________________________________ 0341 gboolean WindowManager::styleSetHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) 0342 { 0343 0344 // get widget from params 0345 GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); 0346 if( !GTK_IS_WIDGET( widget ) ) return FALSE; 0347 0348 // never register widgets that are possibly applets 0349 if( Gtk::gtk_widget_is_applet( widget ) ) return TRUE; 0350 0351 // cast data to window manager 0352 WindowManager &manager( *static_cast<WindowManager*>(data ) ); 0353 0354 bool registered( false ); 0355 if( GTK_IS_WINDOW( widget ) || 0356 GTK_IS_VIEWPORT( widget ) || 0357 GTK_IS_TOOLBAR( widget ) || 0358 GTK_IS_MENU_BAR( widget ) || 0359 GTK_IS_NOTEBOOK( widget ) ) 0360 { 0361 0362 // top-level windows 0363 registered = manager.registerWidget( widget ); 0364 0365 } else if( 0366 Gtk::gtk_button_is_in_path_bar(widget) && 0367 Gtk::g_object_is_a( G_OBJECT( gtk_widget_get_parent( widget ) ), "GtkPathBar" ) ) { 0368 0369 // path bar widgets 0370 registered = manager.registerWidget( widget ); 0371 0372 } 0373 0374 #if OXYGEN_DEBUG 0375 if( registered ) 0376 { 0377 std::cerr 0378 << "Oxygen::WindowManager::styleSetHook -" 0379 << " registering: " << widget 0380 << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0381 << std::endl; 0382 } 0383 #else 0384 // silence the compiler 0385 (void)registered; 0386 #endif 0387 0388 return TRUE; 0389 0390 } 0391 0392 //_________________________________________________________________ 0393 gboolean WindowManager::buttonReleaseHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) 0394 { 0395 0396 // get widget from params 0397 GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); 0398 if( !GTK_IS_WIDGET( widget ) ) return FALSE; 0399 0400 // cast data to window manager 0401 WindowManager &manager( *static_cast<WindowManager*>(data) ); 0402 0403 // check mode 0404 if( manager._dragMode == Disabled ) return TRUE; 0405 0406 // check if drag is in progress, and reset if yes 0407 if( manager._dragAboutToStart || manager._dragInProgress ) 0408 { 0409 0410 #if OXYGEN_DEBUG 0411 std::cerr << "Oxygen::WindowManager::buttonReleaseHook -" 0412 << " widget: " << widget 0413 << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0414 << " " << gtk_widget_get_name( widget ) 0415 << std::endl; 0416 #endif 0417 0418 // reset cursor 0419 if( !manager._useWMMoveResize && manager._dragInProgress ) 0420 { manager.unsetCursor( widget ); } 0421 0422 manager.resetDrag(); 0423 0424 } 0425 0426 return TRUE; 0427 } 0428 0429 //_________________________________________________________________ 0430 bool WindowManager::startDrag( GtkWidget* widget, GdkEventMotion* event ) 0431 { 0432 0433 // make sure drag is enabled 0434 if( !_dragAboutToStart ) return false; 0435 0436 // check displacement with respect to drag start, as long as not already started 0437 if( !_dragInProgress ) 0438 { 0439 const int distance( abs( _globalX - int(event->x_root) ) + abs( _globalY - int(event->y_root) ) ); 0440 0441 if( distance > 0 && _timer.isRunning() ) _timer.stop(); 0442 if( distance < _dragDistance ) return false; 0443 0444 } 0445 0446 // start drag from current position 0447 if( _useWMMoveResize ) 0448 { 0449 0450 return startDrag( widget, int(event->x_root), int(event->y_root), event->time ); 0451 0452 } else { 0453 0454 if( !_dragInProgress ) 0455 { 0456 setCursor( widget ); 0457 _dragInProgress = true; 0458 } 0459 0460 GtkWindow* topLevel = GTK_WINDOW( gtk_widget_get_toplevel( widget ) ); 0461 int wx, wy; 0462 gtk_window_get_position( topLevel, &wx, &wy ); 0463 gtk_window_move( topLevel, wx + event->x - _x, wy + event->y - _y ); 0464 return true; 0465 0466 } 0467 0468 } 0469 0470 //_________________________________________________________________ 0471 bool WindowManager::startDrag( GtkWidget* widget, int x, int y, guint32 time ) 0472 { 0473 0474 // create xevent and send. 0475 if( _useWMMoveResize ) 0476 { 0477 0478 _dragInProgress = true; 0479 GtkWindow* topLevel = GTK_WINDOW( gtk_widget_get_toplevel( widget ) ); 0480 gtk_window_begin_move_drag( topLevel, Gtk::LeftButton, x, y, time ); 0481 resetDrag(); 0482 0483 } else if( !_dragInProgress ) { 0484 0485 _dragInProgress = true; 0486 setCursor( widget ); 0487 0488 } 0489 0490 return true; 0491 0492 } 0493 0494 //_________________________________________________________________ 0495 void WindowManager::setCursor( GtkWidget* widget ) 0496 { 0497 0498 GdkWindow* window( gtk_widget_get_window( gtk_widget_get_toplevel( widget ) ) ); 0499 _oldCursor = gdk_window_get_cursor( window ); 0500 gdk_window_set_cursor( window, _cursor ); 0501 } 0502 0503 //_________________________________________________________________ 0504 void WindowManager::unsetCursor( GtkWidget* widget ) 0505 { 0506 GdkWindow* window( gtk_widget_get_window( gtk_widget_get_toplevel( widget ) ) ); 0507 gdk_window_set_cursor( window, _oldCursor ); 0508 } 0509 0510 //_________________________________________________ 0511 bool WindowManager::resetDrag( void ) 0512 { 0513 0514 _widget = 0L; 0515 _lastRejectedEvent = 0L; 0516 _x = -1; 0517 _y = -1; 0518 _globalX = -1; 0519 _globalY = -1; 0520 _time = 0; 0521 0522 // stop timer 0523 if( _timer.isRunning() ) _timer.stop(); 0524 0525 if( _dragAboutToStart || _dragInProgress ) 0526 { 0527 0528 _dragAboutToStart = false; 0529 _dragInProgress = false; 0530 return true; 0531 0532 } else return false; 0533 0534 } 0535 0536 //_________________________________________________ 0537 bool WindowManager::canDrag( GtkWidget* widget, GdkEventButton* event ) 0538 { 0539 0540 if( _dragMode == Disabled ) return false; 0541 else if( !_dragAboutToStart && checkCursor( event->window ) && withinWidget(widget, event ) && useEvent( widget, event ) ) 0542 { 0543 0544 // store widget and event position 0545 _widget = widget; 0546 _x = int(event->x); 0547 _y = int(event->y); 0548 _globalX = int(event->x_root); 0549 _globalY = int(event->y_root); 0550 _time = event->time; 0551 0552 // start timer 0553 if( _timer.isRunning() ) _timer.stop(); 0554 _timer.start( _dragDelay, (GSourceFunc)startDelayedDrag, this ); 0555 0556 // enable drag and accept 0557 _dragAboutToStart = true; 0558 return true; 0559 0560 } else { 0561 0562 // mark event as rejected 0563 _lastRejectedEvent = event; 0564 return false; 0565 } 0566 0567 } 0568 0569 //_________________________________________________ 0570 bool WindowManager::checkCursor( GdkWindow* window ) const 0571 { 0572 if( !window ) return true; 0573 GdkCursor* cursor = gdk_window_get_cursor( window ); 0574 0575 // do not propagate if widget's cursor is currently modified, 0576 // since it is usually indicative of mouse action 0577 return !cursor || gdk_cursor_get_cursor_type( cursor ) == GDK_ARROW; 0578 0579 } 0580 0581 //_________________________________________________ 0582 bool WindowManager::withinWidget( GtkWidget* widget, GdkEventButton* event ) const 0583 { 0584 0585 // get top level widget 0586 GtkWidget* topLevel( gtk_widget_get_toplevel( widget ) ); 0587 if( !topLevel ) return true; 0588 0589 // get top level window; 0590 GdkWindow *window( gtk_widget_get_window( topLevel ) ); 0591 if( !window ) return true; 0592 0593 // translate widget position to topLevel 0594 int wx(0); 0595 int wy(0); 0596 gtk_widget_translate_coordinates( widget, topLevel, wx, wy, &wx, &wy ); 0597 0598 // translate to absolute coordinates 0599 int nx(0); 0600 int ny(0); 0601 gdk_window_get_origin( window, &nx, &ny ); 0602 wx += nx; 0603 wy += ny; 0604 0605 // get widget size. 0606 GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) ); 0607 0608 // translate event position in 'local' coordinates with respect to widget's window 0609 const int xLocal = int(event->x_root) - wx + allocation.x; 0610 const int yLocal = int(event->y_root) - wy + allocation.y; 0611 0612 if( GTK_IS_NOTEBOOK( widget ) ) 0613 { 0614 0615 GtkAllocation tabbarRect; 0616 Gtk::gtk_notebook_get_tabbar_rect( GTK_NOTEBOOK( widget ), &tabbarRect ); 0617 0618 // compare to event local position 0619 if( !Gtk::gdk_rectangle_contains( &tabbarRect, xLocal, yLocal ) ) return false; 0620 else if( !Style::instance().animations().tabWidgetEngine().contains( widget ) ) return false; 0621 else return !Style::instance().animations().tabWidgetEngine().isInTab( widget, xLocal, yLocal ); 0622 0623 } else { 0624 0625 // compare to event position 0626 return Gtk::gdk_rectangle_contains( &allocation, xLocal, yLocal ); 0627 0628 } 0629 0630 } 0631 0632 //_________________________________________________ 0633 bool WindowManager::useEvent( GtkWidget* widget, GdkEventButton* event ) 0634 { 0635 0636 // check against mode 0637 if( _dragMode == Disabled ) return false; 0638 else if( _dragMode == Minimal && !( GTK_IS_TOOLBAR( widget ) || GTK_IS_MENU_BAR( widget ) ) ) return false; 0639 else if( _lastRejectedEvent && event == _lastRejectedEvent ) return false; 0640 else { 0641 0642 const DragStatus status( childrenUseEvent( widget, event, false ) ); 0643 0644 #if OXYGEN_DEBUG 0645 std::cerr << "Oxygen::WindowManager::useEvent -" 0646 << " event: " << event 0647 << " widget: " << widget 0648 << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" 0649 << " " << gtk_widget_get_name( widget ) 0650 << " status: " << dragStatusString(status) 0651 << std::endl; 0652 #endif 0653 0654 return status == Accepted; 0655 0656 } 0657 0658 } 0659 0660 //_________________________________________________ 0661 std::string WindowManager::dragStatusString( DragStatus status ) const 0662 { 0663 0664 switch( status ) 0665 { 0666 case Accepted: return "accepted"; 0667 case BlackListed: return "widget is black-listed"; 0668 case WidgetIsPrelight: return "widget is prelit"; 0669 case WidgetIsButton: return "widget is a button"; 0670 case WidgetIsMenuItem: return "widget is a menu item"; 0671 case WidgetIsScrolledWindow: return "widget is a scrolled window with focus"; 0672 case WidgetIsTabLabel: return "widget is a notebook's tab label"; 0673 case InvalidWindow: return "widget's window is hidden"; 0674 case InvalidEventMask: return "invalid event mask"; 0675 default: return "unknown"; 0676 } 0677 } 0678 0679 //_________________________________________________ 0680 WindowManager::DragStatus WindowManager::childrenUseEvent( GtkWidget* widget, GdkEventButton* event, bool inNoteBook ) const 0681 { 0682 0683 /* 0684 always reject if 0685 - widget is black listed 0686 - widget is prelit 0687 - widget is an active button 0688 - widget is a menu item 0689 - widget event mask is explicitly set to GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK 0690 */ 0691 if( widgetIsBlackListed( widget ) ) return BlackListed; 0692 else if( gtk_widget_get_state( widget ) == GTK_STATE_PRELIGHT ) return WidgetIsPrelight; 0693 else if( GTK_IS_BUTTON( widget ) ) return WidgetIsButton; 0694 else if( GTK_IS_MENU_ITEM( widget ) ) return WidgetIsMenuItem; 0695 else if( GTK_IS_SCROLLED_WINDOW( widget ) && ( !inNoteBook || gtk_widget_is_focus( widget ) ) ) return WidgetIsScrolledWindow; 0696 0697 // check window 0698 GdkWindow *window = gtk_widget_get_window( widget ); 0699 if( !( window && gdk_window_is_visible( window ) ) ) return InvalidWindow; 0700 0701 // accept if widget is not a container and we got this far, 0702 if( !GTK_IS_CONTAINER( widget ) ) return Accepted; 0703 0704 // check notebook 0705 if( GTK_IS_NOTEBOOK( widget ) ) 0706 { 0707 0708 /* 0709 always reject if 0710 - Notebook has visible scroll arrows 0711 - there is an hovered tab 0712 - notebook is not registered 0713 */ 0714 if( Gtk::gtk_notebook_has_visible_arrows( GTK_NOTEBOOK( widget ) ) || 0715 !Style::instance().animations().tabWidgetEngine().contains( widget ) || 0716 Style::instance().animations().tabWidgetEngine().hoveredTab( widget ) != -1 ) 0717 { return WidgetIsPrelight; } 0718 0719 // keep track on whether we are in a notebook 0720 inNoteBook = true; 0721 } 0722 0723 // loop over children and check 0724 DragStatus status = Accepted; 0725 GList *children = gtk_container_get_children( GTK_CONTAINER( widget ) ); 0726 for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) 0727 { 0728 0729 // cast child to GtkWidget 0730 if( !GTK_IS_WIDGET( child->data ) ) continue; 0731 GtkWidget* childWidget( GTK_WIDGET( child->data ) ); 0732 0733 // check that widget contains event 0734 if( withinWidget( childWidget, event ) ) 0735 { 0736 0737 /* 0738 following checks must not be moved upstream, as they are not to be applied 0739 to the first parent widget (the one that recieved the mouse press event 0740 */ 0741 0742 // always reject if child explicitly accepts button press and button release events 0743 if( gtk_widget_get_events( childWidget ) & (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK) ) 0744 { 0745 0746 status = InvalidEventMask; 0747 0748 } else if( GTK_IS_NOTEBOOK( widget ) && Gtk::gtk_notebook_is_tab_label( GTK_NOTEBOOK( widget ), childWidget ) ) { 0749 0750 // always disable on tabbar label 0751 status = WidgetIsTabLabel; 0752 0753 } else { 0754 0755 // recursive check 0756 status = childrenUseEvent( childWidget, event, inNoteBook ); 0757 0758 } 0759 0760 0761 #if OXYGEN_DEBUG 0762 std::cerr << "Oxygen::WindowManager::childrenUseEvent -" 0763 << " event: " << event 0764 << " widget: " << childWidget 0765 << " (" << G_OBJECT_TYPE_NAME( childWidget ) << ")" 0766 << " " << gtk_widget_get_name( childWidget ) 0767 << " status: " << dragStatusString(status) 0768 << std::endl; 0769 #endif 0770 0771 break; 0772 0773 } 0774 0775 } 0776 0777 // free list 0778 if( children ) g_list_free( children ); 0779 return status; 0780 0781 } 0782 0783 //_________________________________________________ 0784 bool WindowManager::widgetIsBlackListed( GtkWidget* widget ) const 0785 { 0786 BlackList::const_iterator iter( std::find_if( _blackList.begin(), _blackList.end(), BlackListFTor( G_OBJECT( widget ) ) ) ); 0787 #if OXYGEN_DEBUG 0788 if( iter == _blackList.end() ) return false; 0789 else { 0790 0791 std::cerr << "Oxygen::WindowManager::widgetIsBlackListed - widget: " << widget << " type: " << *iter << std::endl; 0792 return true; 0793 0794 } 0795 #else 0796 return iter != _blackList.end(); 0797 #endif 0798 } 0799 0800 //_________________________________________________ 0801 bool WindowManager::widgetHasBlackListedParent( GtkWidget* widget ) const 0802 { 0803 0804 #if OXYGEN_DEBUG 0805 std::cerr << "Oxygen::WindowManager::widgetHasBlackListedParent - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; 0806 #endif 0807 0808 // loop over widget parent 0809 for( GtkWidget* parent = gtk_widget_get_parent( widget ); parent; parent = gtk_widget_get_parent( parent ) ) 0810 { if( _blackListWidgets.find( parent ) != _blackListWidgets.end() ) return true; } 0811 0812 return false; 0813 } 0814 0815 //_________________________________________________ 0816 void WindowManager::initializeBlackList( void ) 0817 { 0818 // clear list 0819 _blackList.clear(); 0820 _blackList.push_back( "GtkScale" ); 0821 _blackList.push_back( "GimpColorBar" ); 0822 _blackList.push_back( "GladeDesignLayout" ); 0823 _blackList.push_back( "GooCanvas" ); 0824 _blackList.push_back( "GtkPizza" ); 0825 _blackList.push_back( "MetaFrames" ); 0826 _blackList.push_back( "SPHRuler" ); 0827 _blackList.push_back( "SPVRuler" ); 0828 _blackList.push_back( "GtkPlug" ); 0829 } 0830 0831 //________________________________________________________________________________ 0832 void WindowManager::connect( GtkWidget* widget, WindowManager::Data& data ) 0833 { 0834 data._destroyId.connect( G_OBJECT( widget ), "destroy", G_CALLBACK( wmDestroy ), this ); 0835 data._pressId.connect( G_OBJECT( widget ), "button-press-event", G_CALLBACK( wmButtonPress ), this ); 0836 data._leaveId.connect( G_OBJECT( widget ), "leave-notify-event", G_CALLBACK( wmLeave ), this ); 0837 data._motionId.connect( G_OBJECT( widget ), "motion-notify-event", G_CALLBACK( wmMotion ), this ); 0838 } 0839 0840 //_________________________________________________ 0841 void WindowManager::Data::disconnect( GtkWidget* ) 0842 { 0843 0844 _leaveId.disconnect(); 0845 _destroyId.disconnect(); 0846 _pressId.disconnect(); 0847 _motionId.disconnect(); 0848 0849 } 0850 0851 }