Fix cursor inheritance and busy cursor/global cursor, closes #15801

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75690 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Paul Cornett
2014-01-23 18:27:13 +00:00
parent 7df4846118
commit 9f09241cd0
7 changed files with 117 additions and 95 deletions

View File

@@ -332,7 +332,7 @@ public:
// set the current cursor for all GdkWindows making part of this widget // set the current cursor for all GdkWindows making part of this widget
// (see GTKGetWindow) // (see GTKGetWindow)
void GTKUpdateCursor(bool update_self = true, bool recurse = true); void GTKUpdateCursor();
// extra (wxGTK-specific) flags // extra (wxGTK-specific) flags
bool m_noExpose:1; // wxGLCanvas has its own redrawing bool m_noExpose:1; // wxGLCanvas has its own redrawing

View File

@@ -308,59 +308,18 @@ wxCursor::CloneGDIRefData(const wxGDIRefData * WXUNUSED(data)) const
// busy cursor routines // 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; static int gs_busyCount = 0;
const wxCursor &wxBusyCursor::GetStoredCursor() void wxBeginBusyCursor(const wxCursor* cursor)
{ {
return gs_savedCursor; if (gs_busyCount++ == 0)
} wxSetCursor(*cursor);
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);
}
} }
void wxEndBusyCursor() void wxEndBusyCursor()
{ {
if (--gs_busyCount > 0) if (gs_busyCount && --gs_busyCount == 0)
return; wxSetCursor(wxCursor());
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);
} }
bool wxIsBusy() bool wxIsBusy()
@@ -368,8 +327,94 @@ bool wxIsBusy()
return gs_busyCount > 0; 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<GdkWindow*>(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<GdkWindow*>(p->data));
}
void wxSetCursor( const wxCursor& cursor ) void wxSetCursor( const wxCursor& cursor )
{ {
g_globalCursor = cursor; GdkDisplay* display = NULL;
UpdateCursors(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);
} }

View File

@@ -12,7 +12,6 @@
#include "wx/dialog.h" #include "wx/dialog.h"
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/cursor.h"
#endif // WX_PRECOMP #endif // WX_PRECOMP
#include "wx/evtloop.h" #include "wx/evtloop.h"
@@ -148,8 +147,6 @@ int wxDialog::ShowModal()
GTK_WINDOW(parent->m_widget) ); GTK_WINDOW(parent->m_widget) );
} }
wxBusyCursorSuspender cs; // temporarily suppress the busy cursor
#if GTK_CHECK_VERSION(2,10,0) #if GTK_CHECK_VERSION(2,10,0)
unsigned sigId = 0; unsigned sigId = 0;
gulong hookId = 0; gulong hookId = 0;

View File

@@ -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)); gdk_window_set_cursor(gtk_widget_get_window(widget), gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER));
else else
gdk_window_set_cursor(gtk_widget_get_window(widget), NULL); gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
win->GTKUpdateCursor(false);
} }
return TRUE; return TRUE;
} }

View File

@@ -823,8 +823,6 @@ bool wxTextCtrl::Create( wxWindow *parent,
GTKConnectClipboardSignals(m_text); GTKConnectClipboardSignals(m_text);
m_cursor = wxCursor( wxCURSOR_IBEAM );
return true; return true;
} }
@@ -1329,7 +1327,6 @@ bool wxTextCtrl::Enable( bool enable )
} }
gtk_widget_set_sensitive( m_text, enable ); gtk_widget_set_sensitive( m_text, enable );
SetCursor(enable ? wxCursor(wxCURSOR_IBEAM) : wxCursor());
return true; 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); gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(m_text), &end, x, y);
if (!gtk_text_iter_has_tag(&end, tag)) if (!gtk_text_iter_has_tag(&end, tag))
{ {
SetCursor(wxCursor(wxCURSOR_IBEAM)); SetCursor(wxCursor());
return; return;
} }

View File

@@ -24,7 +24,6 @@
// data // data
extern bool g_blockEventsOnDrag; extern bool g_blockEventsOnDrag;
extern wxCursor g_globalCursor;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxToolBarTool // wxToolBarTool

View File

@@ -197,7 +197,6 @@ typedef guint KeySym;
bool g_blockEventsOnDrag; bool g_blockEventsOnDrag;
// Don't allow mouse event propagation during scroll // Don't allow mouse event propagation during scroll
bool g_blockEventsOnScroll; bool g_blockEventsOnScroll;
extern wxCursor g_globalCursor;
// mouse capture state: the window which has it and if the mouse is currently // mouse capture state: the window which has it and if the mouse is currently
// inside it // inside it
@@ -2068,7 +2067,7 @@ void wxWindowGTK::GTKHandleRealized()
event.SetEventObject( this ); event.SetEventObject( this );
GTKProcessEvent( event ); GTKProcessEvent( event );
GTKUpdateCursor(true, false); GTKUpdateCursor();
if (m_wxwindow && IsTopLevel()) if (m_wxwindow && IsTopLevel())
{ {
@@ -2259,8 +2258,6 @@ void wxWindowGTK::Init()
m_clipPaintRegion = false; m_clipPaintRegion = false;
m_cursor = *wxSTANDARD_CURSOR;
m_imContext = NULL; m_imContext = NULL;
m_imKeyEvent = NULL; m_imKeyEvent = NULL;
@@ -3663,7 +3660,7 @@ void wxWindowGTK::Lower()
bool wxWindowGTK::SetCursor( const wxCursor &cursor ) bool wxWindowGTK::SetCursor( const wxCursor &cursor )
{ {
if ( !wxWindowBase::SetCursor(cursor.IsOk() ? cursor : *wxSTANDARD_CURSOR) ) if (!wxWindowBase::SetCursor(cursor))
return false; return false;
GTKUpdateCursor(); GTKUpdateCursor();
@@ -3671,38 +3668,30 @@ bool wxWindowGTK::SetCursor( const wxCursor &cursor )
return true; return true;
} }
void wxWindowGTK::GTKUpdateCursor(bool update_self /*=true*/, bool recurse /*=true*/) void wxWindowGTK::GTKUpdateCursor()
{ {
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()); return;
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());
}
}
}
}
} }
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") ); wxCHECK_RET( window, wxT("CaptureMouse() failed") );
const wxCursor* cursor = &m_cursor;
if (!cursor->IsOk())
cursor = wxSTANDARD_CURSOR;
const GdkEventMask mask = GdkEventMask( const GdkEventMask mask = GdkEventMask(
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK |
@@ -4489,12 +4474,12 @@ void wxWindowGTK::DoCaptureMouse()
GdkDevice* device = gdk_device_manager_get_client_pointer(manager); GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
gdk_device_grab( gdk_device_grab(
device, window, GDK_OWNERSHIP_NONE, false, mask, device, window, GDK_OWNERSHIP_NONE, false, mask,
cursor->GetCursor(), unsigned(GDK_CURRENT_TIME)); NULL, unsigned(GDK_CURRENT_TIME));
#else #else
gdk_pointer_grab( window, FALSE, gdk_pointer_grab( window, FALSE,
mask, mask,
NULL, NULL,
cursor->GetCursor(), NULL,
(guint32)GDK_CURRENT_TIME ); (guint32)GDK_CURRENT_TIME );
#endif #endif
g_captureWindow = this; g_captureWindow = this;