diff --git a/docs/changes.txt b/docs/changes.txt index 475fa9575c..0e8ff26343 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -602,6 +602,7 @@ wxGTK: - Fix setting font and colours of wxToggleButtons with images. - Fix wxPopupTransientWindow mouse events with GTK3, also fixes wxOwnerDrawnComboBox, wxDatePickerCtrl. +- Fix cursor inheritance. wxMSW: diff --git a/src/gtk/cursor.cpp b/src/gtk/cursor.cpp index aab088f64a..0a4fca89c9 100644 --- a/src/gtk/cursor.cpp +++ b/src/gtk/cursor.cpp @@ -308,59 +308,18 @@ wxCursor::CloneGDIRefData(const wxGDIRefData * WXUNUSED(data)) const // busy cursor routines //----------------------------------------------------------------------------- -/* Current cursor, in order to hang on to - * cursor handle when setting the cursor globally */ -wxCursor g_globalCursor; - -static wxCursor gs_savedCursor; static int gs_busyCount = 0; -const wxCursor &wxBusyCursor::GetStoredCursor() +void wxBeginBusyCursor(const wxCursor* cursor) { - return gs_savedCursor; -} - -const wxCursor wxBusyCursor::GetBusyCursor() -{ - return wxCursor(wxCURSOR_WATCH); -} - -static void UpdateCursors(GdkDisplay** display) -{ - wxWindowList::const_iterator i = wxTopLevelWindows.begin(); - for (size_t n = wxTopLevelWindows.size(); n--; ++i) - { - wxWindow* win = *i; - win->GTKUpdateCursor(); - if (display && *display == NULL && win->m_widget) - *display = gtk_widget_get_display(win->m_widget); - } + if (gs_busyCount++ == 0) + wxSetCursor(*cursor); } void wxEndBusyCursor() { - if (--gs_busyCount > 0) - return; - - g_globalCursor = gs_savedCursor; - gs_savedCursor = wxNullCursor; - UpdateCursors(NULL); -} - -void wxBeginBusyCursor(const wxCursor* cursor) -{ - if (gs_busyCount++ > 0) - return; - - wxASSERT_MSG( !gs_savedCursor.IsOk(), - wxT("forgot to call wxEndBusyCursor, will leak memory") ); - - gs_savedCursor = g_globalCursor; - g_globalCursor = *cursor; - GdkDisplay* display = NULL; - UpdateCursors(&display); - if (display) - gdk_display_flush(display); + if (gs_busyCount && --gs_busyCount == 0) + wxSetCursor(wxCursor()); } bool wxIsBusy() @@ -368,8 +327,94 @@ bool wxIsBusy() return gs_busyCount > 0; } +// Table holding non-default cursors to be restored when global cursor is unset +WX_DECLARE_HASH_MAP(GdkWindow*, GdkCursor*, wxPointerHash, wxPointerEqual, wxGdkWindowGdkCursorMapBase); +class wxGdkWindowGdkCursorMap: public wxGdkWindowGdkCursorMapBase +{ +public: + ~wxGdkWindowGdkCursorMap(); +}; +static wxGdkWindowGdkCursorMap* gs_windowCursorMap; + +wxGdkWindowGdkCursorMap::~wxGdkWindowGdkCursorMap() +{ + const_iterator i = begin(); + for (size_t n = size(); n--; ++i) + { +#ifdef __WXGTK3__ + g_object_unref(i->second); +#else + gdk_cursor_unref(i->second); +#endif + } +} + +// Set cursor to default for window and all its children, +// recording non-default cursors in gs_windowCursorMap +static void clearCursors(GdkWindow* window) +{ + GdkCursor* cursor = gdk_window_get_cursor(window); + if (cursor) + { +#ifdef __WXGTK3__ + g_object_ref(cursor); +#else + gdk_cursor_ref(cursor); +#endif + (*gs_windowCursorMap)[window] = cursor; + gdk_window_set_cursor(window, NULL); + } + for (const GList* p = gdk_window_peek_children(window); p; p = p->next) + clearCursors(static_cast(p->data)); +} + +// Restore non-default cursors +static void restoreCursors(GdkWindow* window) +{ + wxGdkWindowGdkCursorMap::const_iterator i = gs_windowCursorMap->find(window); + if (i != gs_windowCursorMap->end()) + gdk_window_set_cursor(window, i->second); + for (const GList* p = gdk_window_peek_children(window); p; p = p->next) + restoreCursors(static_cast(p->data)); +} + void wxSetCursor( const wxCursor& cursor ) { - g_globalCursor = cursor; - UpdateCursors(NULL); + GdkDisplay* display = NULL; + wxWindowList::const_iterator i = wxTopLevelWindows.begin(); + for (size_t n = wxTopLevelWindows.size(); n--; ++i) + { + GtkWidget* widget = (*i)->m_widget; + GdkWindow* window; + if (widget && (window = gtk_widget_get_window(widget))) + { + // if setting global cursor + if (cursor.IsOk()) + { + delete gs_windowCursorMap; + gs_windowCursorMap = new wxGdkWindowGdkCursorMap; + // clear all cursors, saving non-default ones for later + clearCursors(window); + // set global cursor + wxASSERT(gdk_window_get_cursor(window) == NULL); + gdk_window_set_cursor(window, cursor.GetCursor()); + } + else + { + // remove global cursor + gdk_window_set_cursor(window, NULL); + if (gs_windowCursorMap) + { + // restore non-default cursors + restoreCursors(window); + delete gs_windowCursorMap; + gs_windowCursorMap = NULL; + } + } + if (display == NULL) + display = gdk_window_get_display(window); + } + } + if (display) + gdk_display_flush(display); } diff --git a/src/gtk/dialog.cpp b/src/gtk/dialog.cpp index 98f08d7d6f..6ad78a8c0e 100644 --- a/src/gtk/dialog.cpp +++ b/src/gtk/dialog.cpp @@ -12,7 +12,6 @@ #include "wx/dialog.h" #ifndef WX_PRECOMP - #include "wx/cursor.h" #endif // WX_PRECOMP #include "wx/evtloop.h" @@ -148,8 +147,6 @@ int wxDialog::ShowModal() GTK_WINDOW(parent->m_widget) ); } - wxBusyCursorSuspender cs; // temporarily suppress the busy cursor - #if GTK_CHECK_VERSION(2,10,0) unsigned sigId = 0; gulong hookId = 0; diff --git a/src/gtk/minifram.cpp b/src/gtk/minifram.cpp index 24c32acaa6..cc897e7970 100644 --- a/src/gtk/minifram.cpp +++ b/src/gtk/minifram.cpp @@ -304,7 +304,6 @@ gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, gdk_window_set_cursor(gtk_widget_get_window(widget), gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER)); else gdk_window_set_cursor(gtk_widget_get_window(widget), NULL); - win->GTKUpdateCursor(false); } return TRUE; } diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 9e5735a48b..dc4d1e710d 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -823,8 +823,6 @@ bool wxTextCtrl::Create( wxWindow *parent, GTKConnectClipboardSignals(m_text); - m_cursor = wxCursor( wxCURSOR_IBEAM ); - return true; } @@ -1329,7 +1327,6 @@ bool wxTextCtrl::Enable( bool enable ) } gtk_widget_set_sensitive( m_text, enable ); - SetCursor(enable ? wxCursor(wxCURSOR_IBEAM) : wxCursor()); return true; } @@ -1989,7 +1986,7 @@ void wxTextCtrl::OnUrlMouseEvent(wxMouseEvent& event) gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(m_text), &end, x, y); if (!gtk_text_iter_has_tag(&end, tag)) { - SetCursor(wxCursor(wxCURSOR_IBEAM)); + SetCursor(wxCursor()); return; } diff --git a/src/gtk/toolbar.cpp b/src/gtk/toolbar.cpp index f19f11d5b2..ebc50a073e 100644 --- a/src/gtk/toolbar.cpp +++ b/src/gtk/toolbar.cpp @@ -24,7 +24,6 @@ // data extern bool g_blockEventsOnDrag; -extern wxCursor g_globalCursor; // ---------------------------------------------------------------------------- // wxToolBarTool diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index a16743410f..d47b973de5 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -197,7 +197,6 @@ typedef guint KeySym; bool g_blockEventsOnDrag; // Don't allow mouse event propagation during scroll bool g_blockEventsOnScroll; -extern wxCursor g_globalCursor; // mouse capture state: the window which has it and if the mouse is currently // inside it @@ -2259,8 +2258,6 @@ void wxWindowGTK::Init() m_clipPaintRegion = false; - m_cursor = *wxSTANDARD_CURSOR; - m_imContext = NULL; m_imKeyEvent = NULL; @@ -3663,7 +3660,7 @@ void wxWindowGTK::Lower() bool wxWindowGTK::SetCursor( const wxCursor &cursor ) { - if ( !wxWindowBase::SetCursor(cursor.IsOk() ? cursor : *wxSTANDARD_CURSOR) ) + if (!wxWindowBase::SetCursor(cursor)) return false; GTKUpdateCursor(); @@ -3671,38 +3668,30 @@ bool wxWindowGTK::SetCursor( const wxCursor &cursor ) return true; } -void wxWindowGTK::GTKUpdateCursor(bool update_self /*=true*/, bool recurse /*=true*/) +void wxWindowGTK::GTKUpdateCursor(bool, bool) { - if (update_self) + if (m_widget == NULL || + !gtk_widget_get_realized(m_widget) || + (m_wxwindow == NULL && !gtk_widget_get_has_window(m_widget))) { - wxCursor cursor(g_globalCursor.IsOk() ? g_globalCursor : GetCursor()); - if ( cursor.IsOk() ) - { - wxArrayGdkWindows windowsThis; - GdkWindow* window = GTKGetWindow(windowsThis); - if (window) - gdk_window_set_cursor( window, cursor.GetCursor() ); - else - { - const size_t count = windowsThis.size(); - for ( size_t n = 0; n < count; n++ ) - { - GdkWindow *win = windowsThis[n]; - // It can be zero if the window has not been realized yet. - if ( win ) - { - gdk_window_set_cursor(win, cursor.GetCursor()); - } - } - } - } + return; } - if (recurse) + GdkCursor* cursor = NULL; + if (m_cursor.IsOk()) + cursor = m_cursor.GetCursor(); + + wxArrayGdkWindows windows; + GdkWindow* window = GTKGetWindow(windows); + if (window) + gdk_window_set_cursor(window, cursor); + else { - for (wxWindowList::iterator it = GetChildren().begin(); it != GetChildren().end(); ++it) + for (size_t i = windows.size(); i--;) { - (*it)->GTKUpdateCursor( true ); + window = windows[i]; + if (window) + gdk_window_set_cursor(window, cursor); } } } @@ -4474,10 +4463,6 @@ void wxWindowGTK::DoCaptureMouse() wxCHECK_RET( window, wxT("CaptureMouse() failed") ); - const wxCursor* cursor = &m_cursor; - if (!cursor->IsOk()) - cursor = wxSTANDARD_CURSOR; - const GdkEventMask mask = GdkEventMask( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -4489,12 +4474,12 @@ void wxWindowGTK::DoCaptureMouse() GdkDevice* device = gdk_device_manager_get_client_pointer(manager); gdk_device_grab( device, window, GDK_OWNERSHIP_NONE, false, mask, - cursor->GetCursor(), unsigned(GDK_CURRENT_TIME)); + NULL, unsigned(GDK_CURRENT_TIME)); #else gdk_pointer_grab( window, FALSE, mask, NULL, - cursor->GetCursor(), + NULL, (guint32)GDK_CURRENT_TIME ); #endif g_captureWindow = this;