X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b3d006af0fca9ba3679f092016cf149c9f6fd06c..b6f802f88a25f62220ce8dbb0f78163dc11041ec:/src/gtk/window.cpp diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 424a219958..a6544f8fe6 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -219,8 +219,6 @@ extern bool g_blockEventsOnDrag; extern bool g_blockEventsOnScroll; extern wxCursor g_globalCursor; -static GdkGC *g_eraseGC = NULL; - // mouse capture state: the window which has it and if the mouse is currently // inside it static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL; @@ -480,8 +478,7 @@ gtk_window_expose_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal // This callback gets called in drawing-idle time under // GTK 2.0, so we don't need to defer anything to idle @@ -991,8 +988,7 @@ gtk_window_key_press_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (!win->m_hasVMT) return FALSE; @@ -1124,10 +1120,6 @@ gtk_window_key_press_callback( GtkWidget *widget, } } - - - - // win is a control: tab can be propagated up if ( !ret && ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && @@ -1152,50 +1144,7 @@ gtk_window_key_press_callback( GtkWidget *widget, ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event ); } - // generate wxID_CANCEL if has been pressed (typically in dialogs) - if ( !ret && - (gdk_event->keyval == GDK_Escape) ) - { - // however only do it if we have a Cancel button in the dialog, - // otherwise the user code may get confused by the events from a - // nonexistent button and, worse, a wxButton might get button event - // from another button which is not really expected - wxWindow *winForCancel = win, - *btnCancel = NULL; - while ( winForCancel ) - { - btnCancel = winForCancel->FindWindow(wxID_CANCEL); - if ( btnCancel ) - { - // found a cancel button - break; - } - - if ( winForCancel->IsTopLevel() ) - { - // no need to look further - break; - } - - // maybe our parent has a cancel button? - winForCancel = winForCancel->GetParent(); - } - - if ( btnCancel ) - { - wxCommandEvent eventClick(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); - eventClick.SetEventObject(btnCancel); - ret = btnCancel->GetEventHandler()->ProcessEvent(eventClick); - } - } - - if (ret) - { - g_signal_stop_emission_by_name (widget, "key_press_event"); - return TRUE; - } - - return FALSE; + return ret; } } @@ -1281,8 +1230,7 @@ gtk_window_key_release_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (!win->m_hasVMT) return FALSE; @@ -1297,11 +1245,7 @@ gtk_window_key_release_callback( GtkWidget *widget, return FALSE; } - if ( !win->GetEventHandler()->ProcessEvent( event ) ) - return FALSE; - - g_signal_stop_emission_by_name (widget, "key_release_event"); - return TRUE; + return win->GetEventHandler()->ProcessEvent(event); } } @@ -1443,42 +1387,82 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y) return win; } +// ---------------------------------------------------------------------------- +// common event handlers helpers +// ---------------------------------------------------------------------------- + +int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const +{ + DEBUG_MAIN_THREAD + + // don't need to install idle handler, its done from "event" signal + + if (!m_hasVMT) + return FALSE; + if (g_blockEventsOnDrag) + return TRUE; + if (g_blockEventsOnScroll) + return TRUE; + + if (!GTKIsOwnWindow(event->window)) + return FALSE; + + return -1; +} + +// overloads for all GDK event types we use here: we need to have this as +// GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact, +// derives from it in the sense that the structs have the same layout +#define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \ + static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \ + { \ + return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \ + } + +wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton) +wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion) +wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing) + +#undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD + +#define wxCOMMON_CALLBACK_PROLOGUE(event, win) \ + const int rc = wxGtkCallbackCommonPrologue(event, win); \ + if ( rc != -1 ) \ + return rc + +// send the wxChildFocusEvent and wxFocusEvent, common code of +// gtk_window_focus_in_callback() and SetFocus() +static bool DoSendFocusEvents(wxWindow *win) +{ + // Notify the parent keeping track of focus for the kbd navigation + // purposes that we got it. + wxChildFocusEvent eventChildFocus(win); + (void)win->GetEventHandler()->ProcessEvent(eventChildFocus); + + wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId()); + eventFocus.SetEventObject(win); + + return win->GetEventHandler()->ProcessEvent(eventFocus); +} + +// all event handlers must have C linkage as they're called from GTK+ C code +extern "C" +{ + //----------------------------------------------------------------------------- // "button_press_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - -/* - wxPrintf( wxT("1) OnButtonPress from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(".\n") ); -*/ - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return TRUE; - if (g_blockEventsOnScroll) return TRUE; - - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus()) { gtk_widget_grab_focus( win->m_wxwindow ); -/* - wxPrintf( wxT("GrabFocus from ") ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - wxPrintf( win->GetClassInfo()->GetClassName() ); - wxPrintf( wxT(".\n") ); -*/ } // GDK sends surplus button down events @@ -1613,7 +1597,6 @@ gtk_window_button_press_callback( GtkWidget *widget, if (win->GetEventHandler()->ProcessEvent( event )) { - g_signal_stop_emission_by_name (widget, "button_press_event"); return TRUE; } @@ -1636,28 +1619,17 @@ gtk_window_button_press_callback( GtkWidget *widget, return FALSE; } -} //----------------------------------------------------------------------------- // "button_release_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - if (g_blockEventsOnScroll) return FALSE; - - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); wxEventType event_type = wxEVT_NULL; @@ -1695,36 +1667,19 @@ gtk_window_button_release_callback( GtkWidget *widget, event.SetEventObject( win ); event.SetId( win->GetId() ); - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "button_release_event"); - return TRUE; - } - - return FALSE; -} + return win->GetEventHandler()->ProcessEvent(event); } //----------------------------------------------------------------------------- // "motion_notify_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; - if (g_blockEventsOnScroll) return FALSE; - - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); if (gdk_event->is_hint) { @@ -1736,13 +1691,6 @@ gtk_window_motion_notify_callback( GtkWidget *widget, gdk_event->y = y; } -/* - printf( "OnMotion from " ); - if (win->GetClassInfo() && win->GetClassInfo()->GetClassName()) - printf( win->GetClassInfo()->GetClassName() ); - printf( ".\n" ); -*/ - wxMouseEvent event( wxEVT_MOTION ); InitMouseEvent(win, event, gdk_event); @@ -1785,28 +1733,19 @@ gtk_window_motion_notify_callback( GtkWidget *widget, } } - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "motion_notify_event"); - return TRUE; - } - - return FALSE; -} + return win->GetEventHandler()->ProcessEvent(event); } //----------------------------------------------------------------------------- // "scroll_event", (mouse wheel event) //----------------------------------------------------------------------------- -extern "C" { static gboolean window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win) { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (gdk_event->direction != GDK_SCROLL_UP && gdk_event->direction != GDK_SCROLL_DOWN) @@ -1841,43 +1780,22 @@ window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win) return win->GetEventHandler()->ProcessEvent(event); } -} //----------------------------------------------------------------------------- // "popup-menu" //----------------------------------------------------------------------------- -extern "C" { + static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win) { - wxContextMenuEvent event( - wxEVT_CONTEXT_MENU, - win->GetId(), - wxPoint(-1, -1)); + wxContextMenuEvent event(wxEVT_CONTEXT_MENU, win->GetId(), wxPoint(-1, -1)); event.SetEventObject(win); return win->GetEventHandler()->ProcessEvent(event); } -} //----------------------------------------------------------------------------- // "focus_in_event" //----------------------------------------------------------------------------- -// send the wxChildFocusEvent and wxFocusEvent, common code of -// gtk_window_focus_in_callback() and SetFocus() -static bool DoSendFocusEvents(wxWindow *win) -{ - // Notify the parent keeping track of focus for the kbd navigation - // purposes that we got it. - wxChildFocusEvent eventChildFocus(win); - (void)win->GetEventHandler()->ProcessEvent(eventChildFocus); - - wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId()); - eventFocus.SetEventObject(win); - - return win->GetEventHandler()->ProcessEvent(eventFocus); -} - -extern "C" { static gboolean gtk_window_focus_in_callback( GtkWidget *widget, GdkEventFocus *WXUNUSED(event), @@ -1885,8 +1803,7 @@ gtk_window_focus_in_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (win->m_imData) gtk_im_context_focus_in(win->m_imData->context); @@ -1931,13 +1848,11 @@ gtk_window_focus_in_callback( GtkWidget *widget, return FALSE; } -} //----------------------------------------------------------------------------- // "focus_out_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, @@ -1945,8 +1860,7 @@ gtk_window_focus_out_callback( GtkWidget *widget, { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal if (win->m_imData) gtk_im_context_focus_out(win->m_imData->context); @@ -1998,31 +1912,21 @@ gtk_window_focus_out_callback( GtkWidget *widget, return FALSE; } -} //----------------------------------------------------------------------------- // "enter_notify_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); // Event was emitted after a grab if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE; - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; - int x = 0; int y = 0; GdkModifierType state = (GdkModifierType)0; @@ -2044,39 +1948,23 @@ gtk_window_enter_callback( GtkWidget *widget, } } - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "enter_notify_event"); - return TRUE; - } - - return FALSE; -} + return win->GetEventHandler()->ProcessEvent(event); } //----------------------------------------------------------------------------- // "leave_notify_event" //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win ) { - DEBUG_MAIN_THREAD - - if (g_isIdle) - wxapp_install_idle_handler(); - - if (!win->m_hasVMT) return FALSE; - if (g_blockEventsOnDrag) return FALSE; + wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win); // Event was emitted after an ungrab if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE; - if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE; - wxMouseEvent event( wxEVT_LEAVE_WINDOW ); event.SetTimestamp( gdk_event->time ); event.SetEventObject( win ); @@ -2099,21 +1987,13 @@ gtk_window_leave_callback( GtkWidget *widget, event.m_x = x + pt.x; event.m_y = y + pt.y; - if (win->GetEventHandler()->ProcessEvent( event )) - { - g_signal_stop_emission_by_name (widget, "leave_notify_event"); - return TRUE; - } - - return FALSE; -} + return win->GetEventHandler()->ProcessEvent(event); } //----------------------------------------------------------------------------- // "value_changed" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static void gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win) { @@ -2122,42 +2002,42 @@ gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win) { // Convert scroll event type to scrollwin event type eventType += wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP; - const int orient = range == win->m_scrollBar[0] ? wxHORIZONTAL : wxVERTICAL; - const int i = orient == wxVERTICAL; + + // find the scrollbar which generated the event + wxWindowGTK::ScrollDir dir = win->ScrollDirFromRange(range); + + // generate the corresponding wx event + const int orient = win->OrientFromScrollDir(dir); wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient); event.SetEventObject(win); - win->m_blockValueChanged[i] = true; + + win->m_blockValueChanged[dir] = true; win->GetEventHandler()->ProcessEvent(event); - win->m_blockValueChanged[i] = false; + win->m_blockValueChanged[dir] = false; } } -} //----------------------------------------------------------------------------- // "button_press_event" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win) { DEBUG_MAIN_THREAD - if (g_isIdle) - wxapp_install_idle_handler(); + // don't need to install idle handler, its done from "event" signal g_blockEventsOnScroll = true; win->m_mouseButtonDown = true; return false; } -} //----------------------------------------------------------------------------- // "event_after" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static void gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win) { @@ -2165,19 +2045,18 @@ gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win) { g_signal_handlers_block_by_func(range, (void*)gtk_scrollbar_event_after, win); - const int orient = range == win->m_scrollBar[0] ? wxHORIZONTAL : wxVERTICAL; + const int orient = win->OrientFromScrollDir( + win->ScrollDirFromRange(range)); wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient); event.SetEventObject(win); win->GetEventHandler()->ProcessEvent(event); } } -} //----------------------------------------------------------------------------- // "button_release_event" from scrollbar //----------------------------------------------------------------------------- -extern "C" { static gboolean gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win) { @@ -2197,18 +2076,6 @@ gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* w return false; } -} - -// ---------------------------------------------------------------------------- -// this wxWindowBase function is implemented here (in platform-specific file) -// because it is static and so couldn't be made virtual -// ---------------------------------------------------------------------------- - -wxWindow *wxWindowBase::DoFindFocus() -{ - // the cast is necessary when we compile in wxUniversal mode - return (wxWindow *)g_focusWindow; -} //----------------------------------------------------------------------------- // "realize" from m_widget @@ -2217,7 +2084,6 @@ wxWindow *wxWindowBase::DoFindFocus() /* We cannot set colours and fonts before the widget has been realized, so we do this directly after realization. */ -extern "C" { static void gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) { @@ -2237,13 +2103,11 @@ gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win ) event.SetEventObject( win ); win->GetEventHandler()->ProcessEvent( event ); } -} //----------------------------------------------------------------------------- // "size_allocate" //----------------------------------------------------------------------------- -extern "C" { static void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation *WXUNUSED(alloc), @@ -2268,7 +2132,6 @@ void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), win->GetEventHandler()->ProcessEvent( event ); } } -} #ifdef HAVE_XIM @@ -2278,8 +2141,6 @@ void gtk_window_size_callback( GtkWidget *WXUNUSED(widget), #endif /* Resize XIM window */ - -extern "C" { static void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), GtkAllocation* WXUNUSED_UNLESS_XIM(alloc), @@ -2303,7 +2164,6 @@ void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), } #endif // HAVE_XIM } -} //----------------------------------------------------------------------------- // "realize" from m_wxwindow @@ -2311,7 +2171,6 @@ void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget), /* Initialize XIM support */ -extern "C" { static void gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), wxWindowGTK * WXUNUSED_UNLESS_XIM(win) ) @@ -2396,6 +2255,18 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget), } #endif // HAVE_XIM } + +} // extern "C" + +// ---------------------------------------------------------------------------- +// this wxWindowBase function is implemented here (in platform-specific file) +// because it is static and so couldn't be made virtual +// ---------------------------------------------------------------------------- + +wxWindow *wxWindowBase::DoFindFocus() +{ + // the cast is necessary when we compile in wxUniversal mode + return (wxWindow *)g_focusWindow; } //----------------------------------------------------------------------------- @@ -2488,6 +2359,8 @@ void wxWindowGTK::Init() m_hasVMT = false; m_needParent = true; m_isBeingDeleted = false; + + m_showOnIdle= false; m_noExpose = false; m_nativeSizeEvent = false; @@ -2497,12 +2370,13 @@ void wxWindowGTK::Init() m_mouseButtonDown = false; m_blockScrollEvent = false; - m_scrollBar[0] = - m_scrollBar[1] = NULL; - m_scrollPos[0] = - m_scrollPos[1] = 0; - m_blockValueChanged[0] = - m_blockValueChanged[1] = false; + // initialize scrolling stuff + for ( int dir = 0; dir < ScrollDir_Max; dir++ ) + { + m_scrollBar[dir] = NULL; + m_scrollPos[dir] = 0; + m_blockValueChanged[dir] = false; + } m_oldClientWidth = m_oldClientHeight = 0; @@ -2567,8 +2441,8 @@ bool wxWindowGTK::Create( wxWindow *parent, gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); - m_scrollBar[0] = GTK_RANGE(scrolledWindow->hscrollbar); - m_scrollBar[1] = GTK_RANGE(scrolledWindow->vscrollbar); + m_scrollBar[ScrollDir_Horz] = GTK_RANGE(scrolledWindow->hscrollbar); + m_scrollBar[ScrollDir_Vert] = GTK_RANGE(scrolledWindow->vscrollbar); m_wxwindow = gtk_pizza_new(); @@ -2598,31 +2472,25 @@ bool wxWindowGTK::Create( wxWindow *parent, GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS ); m_acceptsFocus = true; - // these handlers block mouse events to any window during scrolling such as - // motion events and prevent GTK and wxWidgets from fighting over where the - // slider should be - g_signal_connect(m_scrollBar[0], "button_press_event", - G_CALLBACK(gtk_scrollbar_button_press_event), this); - g_signal_connect(m_scrollBar[1], "button_press_event", - G_CALLBACK(gtk_scrollbar_button_press_event), this); - g_signal_connect(m_scrollBar[0], "button_release_event", - G_CALLBACK(gtk_scrollbar_button_release_event), this); - g_signal_connect(m_scrollBar[1], "button_release_event", - G_CALLBACK(gtk_scrollbar_button_release_event), this); - gulong handler_id; - handler_id = g_signal_connect( - m_scrollBar[0], "event_after", G_CALLBACK(gtk_scrollbar_event_after), this); - g_signal_handler_block(m_scrollBar[0], handler_id); - handler_id = g_signal_connect( - m_scrollBar[1], "event_after", G_CALLBACK(gtk_scrollbar_event_after), this); - g_signal_handler_block(m_scrollBar[1], handler_id); - - // these handlers get notified when scrollbar slider moves - - g_signal_connect(m_scrollBar[0], "value_changed", - G_CALLBACK(gtk_scrollbar_value_changed), this); - g_signal_connect(m_scrollBar[1], "value_changed", - G_CALLBACK(gtk_scrollbar_value_changed), this); + // connect various scroll-related events + for ( int dir = 0; dir < ScrollDir_Max; dir++ ) + { + // these handlers block mouse events to any window during scrolling + // such as motion events and prevent GTK and wxWidgets from fighting + // over where the slider should be + g_signal_connect(m_scrollBar[dir], "button_press_event", + G_CALLBACK(gtk_scrollbar_button_press_event), this); + g_signal_connect(m_scrollBar[dir], "button_release_event", + G_CALLBACK(gtk_scrollbar_button_release_event), this); + + gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after", + G_CALLBACK(gtk_scrollbar_event_after), this); + g_signal_handler_block(m_scrollBar[dir], handler_id); + + // these handlers get notified when scrollbar slider moves + g_signal_connect(m_scrollBar[dir], "value_changed", + G_CALLBACK(gtk_scrollbar_value_changed), this); + } gtk_widget_show( m_wxwindow ); @@ -2993,8 +2861,32 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags m_resizing = false; } +bool wxWindowGTK::GtkShowFromOnIdle() +{ + if (IsShown() && m_showOnIdle && !GTK_WIDGET_VISIBLE (m_widget)) + { + GtkAllocation alloc; + alloc.x = m_x; + alloc.y = m_y; + alloc.width = m_width; + alloc.height = m_height; + gtk_widget_size_allocate( m_widget, &alloc ); + gtk_widget_show( m_widget ); + wxShowEvent eventShow(GetId(), true); + eventShow.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventShow); + m_showOnIdle = false; + return true; + } + + return false; +} + void wxWindowGTK::OnInternalIdle() { + // Check if we have to show window now + if (GtkShowFromOnIdle()) return; + if ( m_dirtyTabOrder ) { m_dirtyTabOrder = false; @@ -3008,10 +2900,7 @@ void wxWindowGTK::OnInternalIdle() SetBackgroundStyle(GetBackgroundStyle()); m_needsStyleChange = false; } - - // Update invalidated regions. - GtkUpdate(); - + wxCursor cursor = m_cursor; if (g_globalCursor.Ok()) cursor = g_globalCursor; @@ -3218,14 +3107,22 @@ bool wxWindowGTK::Show( bool show ) } if (show) - gtk_widget_show( m_widget ); + { + if (!m_showOnIdle) + { + gtk_widget_show( m_widget ); + wxShowEvent eventShow(GetId(), show); + eventShow.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventShow); + } + } else + { gtk_widget_hide( m_widget ); - - wxShowEvent eventShow(GetId(), show); - eventShow.SetEventObject(this); - - GetEventHandler()->ProcessEvent(eventShow); + wxShowEvent eventShow(GetId(), show); + eventShow.SetEventObject(this); + GetEventHandler()->ProcessEvent(eventShow); + } return true; } @@ -3377,6 +3274,22 @@ void wxWindowGTK::GetTextExtent( const wxString& string, g_object_unref (layout); } +bool wxWindowGTK::GTKSetDelayedFocusIfNeeded() +{ + if ( g_delayedFocus == this ) + { + if ( GTK_WIDGET_REALIZED(m_widget) ) + { + gtk_widget_grab_focus(m_widget); + g_delayedFocus = NULL; + + return true; + } + } + + return false; +} + void wxWindowGTK::SetFocus() { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); @@ -3463,6 +3376,12 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase ) if (newParent) { + if (GTK_WIDGET_VISIBLE (newParent->m_widget)) + { + m_showOnIdle = true; + gtk_widget_hide( m_widget ); + } + /* insert GTK representation */ (*(newParent->m_insertCallback))(newParent, this); } @@ -3622,10 +3541,36 @@ bool wxWindowGTK::SetCursor( const wxCursor &cursor ) if (g_isIdle) wxapp_install_idle_handler(); - if (cursor == wxNullCursor) - return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR ); - else - return wxWindowBase::SetCursor( cursor ); + return wxWindowBase::SetCursor( cursor.Ok() ? cursor : *wxSTANDARD_CURSOR ); +} + +void wxWindowGTK::GTKUpdateCursor() +{ + wxCursor cursor(g_globalCursor.Ok() ? g_globalCursor : GetCursor()); + if ( cursor.Ok() ) + { + wxArrayGdkWindows windowsThis; + GdkWindow * const winThis = GTKGetWindow(windowsThis); + if ( winThis ) + { + gdk_window_set_cursor(winThis, cursor.GetCursor()); + } + else + { + const size_t count = windowsThis.size(); + for ( size_t n = 0; n < count; n++ ) + { + GdkWindow *win = windowsThis[n]; + if ( !win ) + { + wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?")); + continue; + } + + gdk_window_set_cursor(win, cursor.GetCursor()); + } + } + } } void wxWindowGTK::WarpPointer( int x, int y ) @@ -3645,34 +3590,49 @@ void wxWindowGTK::WarpPointer( int x, int y ) gdk_window_warp_pointer( window, x, y ); } -bool wxWindowGTK::ScrollLines(int lines) +wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const { - bool changed = false; - GtkRange* range = m_scrollBar[1]; - if (range != NULL) + // find the scrollbar which generated the event + for ( int dir = 0; dir < ScrollDir_Max; dir++ ) { - GtkAdjustment* adj = range->adjustment; - const int pos = int(adj->value + 0.5); - gtk_range_set_value(range, pos + lines); - changed = pos != int(adj->value + 0.5); + if ( range == m_scrollBar[dir] ) + return (ScrollDir)dir; } - return changed; + + wxFAIL_MSG( _T("event from unknown scrollbar received") ); + + return ScrollDir_Max; } -bool wxWindowGTK::ScrollPages(int pages) +bool wxWindowGTK::DoScrollByUnits(ScrollDir dir, ScrollUnit unit, int units) { bool changed = false; - GtkRange* range = m_scrollBar[1]; - if (range != NULL) + GtkRange* range = m_scrollBar[dir]; + if ( range && units ) { GtkAdjustment* adj = range->adjustment; - const int pos = int(adj->value + 0.5); - gtk_range_set_value(range, pos + pages * adj->page_size); - changed = pos != int(adj->value + 0.5); + gdouble inc = unit == ScrollUnit_Line ? adj->step_increment + : adj->page_increment; + + const int posOld = int(adj->value + 0.5); + gtk_range_set_value(range, posOld + units*inc); + + changed = int(adj->value + 0.5) != posOld; } + return changed; } +bool wxWindowGTK::ScrollLines(int lines) +{ + return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Line, lines); +} + +bool wxWindowGTK::ScrollPages(int pages) +{ + return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Page, pages); +} + void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) { if (!m_widget) @@ -3682,6 +3642,8 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect ) if (m_wxwindow) { + if (!GTK_PIZZA(m_wxwindow)->bin_window) return; + GdkRectangle gdk_rect, *p; if (rect) @@ -3716,6 +3678,8 @@ void wxWindowGTK::GtkUpdate() { if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window) gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE ); + if (m_widget && m_widget->window) + gdk_window_process_updates( m_widget->window, FALSE ); // for consistency with other platforms (and also because it's convenient // to be able to update an entire TLW by calling Update() only once), we @@ -4020,12 +3984,18 @@ GtkWidget* wxWindowGTK::GetConnectWidget() return connect_widget; } -bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window ) +bool wxWindowGTK::GTKIsOwnWindow(GdkWindow *window) const { - if (m_wxwindow) - return (window == GTK_PIZZA(m_wxwindow)->bin_window); + wxArrayGdkWindows windowsThis; + GdkWindow * const winThis = GTKGetWindow(windowsThis); - return (window == m_widget->window); + return winThis ? window == winThis + : windowsThis.Index(window) != wxNOT_FOUND; +} + +GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const +{ + return m_wxwindow ? GTK_PIZZA(m_wxwindow)->bin_window : m_widget->window; } bool wxWindowGTK::SetFont( const wxFont &font ) @@ -4114,8 +4084,11 @@ void wxWindowGTK::UnblockScrollEvent() m_blockScrollEvent = false; } -void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible, - int range, bool ) +void wxWindowGTK::SetScrollbar(int orient, + int pos, + int thumbVisible, + int range, + bool WXUNUSED(update)) { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); @@ -4135,8 +4108,7 @@ void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible, pos = range - thumbVisible; if (pos < 0) pos = 0; - const int i = orient == wxVERTICAL; - GtkAdjustment* adj = m_scrollBar[i]->adjustment; + GtkAdjustment* adj = m_scrollBar[ScrollDirFromOrient(orient)]->adjustment; adj->step_increment = 1; adj->page_increment = adj->page_size = thumbVisible; @@ -4145,7 +4117,7 @@ void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible, gtk_adjustment_changed(adj); } -void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) +void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh)) { wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); @@ -4154,30 +4126,29 @@ void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) // will not move smoothly while tracking when using wxScrollHelper. if (GetScrollPos(orient) != pos) { - const int i = orient == wxVERTICAL; - GtkAdjustment* adj = m_scrollBar[i]->adjustment; + const int dir = ScrollDirFromOrient(orient); + GtkAdjustment* adj = m_scrollBar[dir]->adjustment; const int max = int(adj->upper - adj->page_size); if (pos > max) pos = max; if (pos < 0) pos = 0; - m_scrollPos[i] = + m_scrollPos[dir] = adj->value = pos; // If a "value_changed" signal emission is not already in progress - if (!m_blockValueChanged[i]) + if (!m_blockValueChanged[dir]) { gtk_adjustment_value_changed(adj); } } } -int wxWindowGTK::GetScrollThumb( int orient ) const +int wxWindowGTK::GetScrollThumb(int orient) const { wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") ); wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") ); - const int i = orient == wxVERTICAL; - return int(m_scrollBar[i]->adjustment->page_size); + return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->page_size); } int wxWindowGTK::GetScrollPos( int orient ) const @@ -4185,8 +4156,7 @@ int wxWindowGTK::GetScrollPos( int orient ) const wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") ); wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") ); - const int i = orient == wxVERTICAL; - return int(m_scrollBar[i]->adjustment->value + 0.5); + return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->value + 0.5); } int wxWindowGTK::GetScrollRange( int orient ) const @@ -4194,8 +4164,7 @@ int wxWindowGTK::GetScrollRange( int orient ) const wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") ); wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") ); - const int i = orient == wxVERTICAL; - return int(m_scrollBar[i]->adjustment->upper); + return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->upper); } // Determine if increment is the same as +/-x, allowing for some small @@ -4348,32 +4317,3 @@ void wxRemoveGrab(wxWindow* window) gtk_grab_remove( (GtkWidget*) window->GetHandle() ); } -// ---------------------------------------------------------------------------- -// wxWinModule -// ---------------------------------------------------------------------------- - -class wxWinModule : public wxModule -{ -public: - bool OnInit(); - void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxWinModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule) - -bool wxWinModule::OnInit() -{ - // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() ); - // gdk_gc_set_fill( g_eraseGC, GDK_SOLID ); - - return true; -} - -void wxWinModule::OnExit() -{ - if (g_eraseGC) - g_object_unref (g_eraseGC); -}