Different fix for cursor inheritance and busy cursor/global cursor.

Previous work was not compatible with GTK < 2.18 and did not properly handle some cases
see #15801


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_3_0_BRANCH@75807 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Paul Cornett
2014-02-06 04:43:46 +00:00
parent f6b9932195
commit 6d9817ea26
5 changed files with 106 additions and 123 deletions

View File

@@ -330,9 +330,7 @@ public:
// find the direction of the given scrollbar (must be one of ours) // find the direction of the given scrollbar (must be one of ours)
ScrollDir ScrollDirFromRange(GtkRange *range) const; ScrollDir ScrollDirFromRange(GtkRange *range) const;
// set the current cursor for all GdkWindows making part of this widget void GTKUpdateCursor(bool isBusyOrGlobalCursor = false, bool isRealize = false);
// (see GTKGetWindow)
void GTKUpdateCursor(bool update_self = true, bool recurse = true);
// 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

@@ -283,7 +283,10 @@ void wxCursor::InitFromImage( const wxImage & image )
GdkCursor *wxCursor::GetCursor() const GdkCursor *wxCursor::GetCursor() const
{ {
return M_CURSORDATA->m_cursor; GdkCursor* cursor = NULL;
if (m_refData)
cursor = M_CURSORDATA->m_cursor;
return cursor;
} }
wxGDIRefData *wxCursor::CreateGDIRefData() const wxGDIRefData *wxCursor::CreateGDIRefData() const
@@ -308,119 +311,43 @@ wxCursor::CloneGDIRefData(const wxGDIRefData * WXUNUSED(data)) const
// busy cursor routines // busy cursor routines
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
wxCursor g_globalCursor;
wxCursor g_busyCursor;
static wxCursor gs_storedCursor;
static int gs_busyCount = 0; static int gs_busyCount = 0;
const wxCursor &wxBusyCursor::GetStoredCursor() const wxCursor& wxBusyCursor::GetStoredCursor()
{ {
static wxCursor s_storedCursor; return gs_storedCursor;
return s_storedCursor;
} }
const wxCursor wxBusyCursor::GetBusyCursor() const wxCursor wxBusyCursor::GetBusyCursor()
{ {
return wxCursor(wxCURSOR_WATCH); return g_busyCursor;
} }
void wxBeginBusyCursor(const wxCursor* cursor) static void UpdateCursors(wxWindow* win, bool isBusyOrGlobalCursor)
{ {
if (gs_busyCount++ == 0) win->GTKUpdateCursor(isBusyOrGlobalCursor);
wxSetCursor(*cursor); const wxWindowList& children = win->GetChildren();
wxWindowList::const_iterator i = children.begin();
for (size_t n = children.size(); n--; ++i)
UpdateCursors(*i, isBusyOrGlobalCursor);
} }
void wxEndBusyCursor() static void SetGlobalCursor(const wxCursor& cursor)
{
if (gs_busyCount && --gs_busyCount == 0)
wxSetCursor(wxCursor());
}
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<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 )
{ {
GdkCursor* gdk_cursor = cursor.GetCursor();
GdkDisplay* display = NULL; GdkDisplay* display = NULL;
wxWindowList::const_iterator i = wxTopLevelWindows.begin(); wxWindowList::const_iterator i = wxTopLevelWindows.begin();
for (size_t n = wxTopLevelWindows.size(); n--; ++i) for (size_t n = wxTopLevelWindows.size(); n--; ++i)
{ {
GtkWidget* widget = (*i)->m_widget; wxWindow* win = *i;
GdkWindow* window; GdkWindow* window;
if (widget && (window = gtk_widget_get_window(widget))) if (win->m_widget && (window = gtk_widget_get_window(win->m_widget)))
{ {
// if setting global cursor gdk_window_set_cursor(window, gdk_cursor);
if (cursor.IsOk()) UpdateCursors(win, gdk_cursor != NULL);
{
delete gs_windowCursorMap;
gs_windowCursorMap = new wxGdkWindowGdkCursorMap;
// clear all cursors, saving non-default ones for later
clearCursors(window);
// set global cursor
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) if (display == NULL)
display = gdk_window_get_display(window); display = gdk_window_get_display(window);
} }
@@ -428,3 +355,35 @@ void wxSetCursor( const wxCursor& cursor )
if (display) if (display)
gdk_display_flush(display); gdk_display_flush(display);
} }
void wxBeginBusyCursor(const wxCursor* cursor)
{
if (gs_busyCount++ == 0)
{
g_busyCursor = *cursor;
gs_storedCursor = g_globalCursor;
SetGlobalCursor(*cursor);
}
}
void wxEndBusyCursor()
{
if (gs_busyCount && --gs_busyCount == 0)
{
g_globalCursor = gs_storedCursor;
gs_storedCursor =
g_busyCursor = wxCursor();
SetGlobalCursor(g_globalCursor);
}
}
bool wxIsBusy()
{
return gs_busyCount > 0;
}
void wxSetCursor( const wxCursor& cursor )
{
g_globalCursor = cursor;
SetGlobalCursor(cursor);
}

View File

@@ -160,15 +160,15 @@ int wxDialog::ShowModal()
} }
#endif #endif
// NOTE: this will cause a gtk_grab_add() during Show()
gtk_window_set_modal(GTK_WINDOW(m_widget), true);
Show( true ); Show( true );
m_modalShowing = true; m_modalShowing = true;
wxOpenModalDialogLocker modalLock; wxOpenModalDialogLocker modalLock;
// NOTE: gtk_window_set_modal internally calls gtk_grab_add() !
gtk_window_set_modal(GTK_WINDOW(m_widget), TRUE);
// Run modal dialog event loop. // Run modal dialog event loop.
{ {
wxGUIEventLoopTiedPtr modal(&m_modalLoop, new wxGUIEventLoop()); wxGUIEventLoopTiedPtr modal(&m_modalLoop, new wxGUIEventLoop());

View File

@@ -74,6 +74,9 @@ static wxTopLevelWindowGTK *g_lastActiveFrame = NULL;
// send any activate events at all // send any activate events at all
static int g_sendActivateEvent = -1; static int g_sendActivateEvent = -1;
extern wxCursor g_globalCursor;
extern wxCursor g_busyCursor;
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
// Whether _NET_REQUEST_FRAME_EXTENTS support is working // Whether _NET_REQUEST_FRAME_EXTENTS support is working
static enum { static enum {
@@ -351,15 +354,22 @@ void wxTopLevelWindowGTK::GTKHandleRealized()
{ {
wxNonOwnedWindow::GTKHandleRealized(); wxNonOwnedWindow::GTKHandleRealized();
gdk_window_set_decorations(gtk_widget_get_window(m_widget), GdkWindow* window = gtk_widget_get_window(m_widget);
(GdkWMDecoration)m_gdkDecor);
gdk_window_set_functions(gtk_widget_get_window(m_widget), gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
(GdkWMFunction)m_gdkFunc); gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
const wxIconBundle& icons = GetIcons(); const wxIconBundle& icons = GetIcons();
if (icons.GetIconCount()) if (icons.GetIconCount())
SetIcons(icons); SetIcons(icons);
GdkCursor* cursor = g_globalCursor.GetCursor();
if (wxIsBusy() && !gtk_window_get_modal(GTK_WINDOW(m_widget)))
cursor = g_busyCursor.GetCursor();
if (cursor)
gdk_window_set_cursor(window, cursor);
#ifdef __WXGTK3__ #ifdef __WXGTK3__
if (gtk_window_get_has_resize_grip(GTK_WINDOW(m_widget))) if (gtk_window_get_has_resize_grip(GTK_WINDOW(m_widget)))
{ {

View File

@@ -197,6 +197,7 @@ 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
@@ -2067,7 +2068,7 @@ void wxWindowGTK::GTKHandleRealized()
event.SetEventObject( this ); event.SetEventObject( this );
GTKProcessEvent( event ); GTKProcessEvent( event );
GTKUpdateCursor(true, false); GTKUpdateCursor(false, true);
if (m_wxwindow && IsTopLevel()) if (m_wxwindow && IsTopLevel())
{ {
@@ -3663,35 +3664,50 @@ bool wxWindowGTK::SetCursor( const wxCursor &cursor )
if (!wxWindowBase::SetCursor(cursor)) if (!wxWindowBase::SetCursor(cursor))
return false; return false;
if (m_cursor.IsOk()) GTKUpdateCursor();
GTKUpdateCursor();
return true; return true;
} }
void wxWindowGTK::GTKUpdateCursor(bool, bool) void wxWindowGTK::GTKUpdateCursor(bool isBusyOrGlobalCursor, bool isRealize)
{ {
if (m_widget == NULL || !gtk_widget_get_realized(m_widget)) if (m_widget == NULL || !gtk_widget_get_realized(m_widget))
return; return;
GdkCursor* cursor = NULL; // if we don't already know there is a busy/global cursor, we have to check for one
if (m_cursor.IsOk()) if (!isBusyOrGlobalCursor)
cursor = m_cursor.GetCursor();
wxArrayGdkWindows windows;
GdkWindow* window = GTKGetWindow(windows);
if (window)
gdk_window_set_cursor(window, cursor);
else
{ {
for (size_t i = windows.size(); i--;) if (g_globalCursor.IsOk())
isBusyOrGlobalCursor = true;
else if (wxIsBusy())
{ {
window = windows[i]; wxWindow* win = wxGetTopLevelParent(this);
if (window) if (win && win->m_widget && !gtk_window_get_modal(GTK_WINDOW(win->m_widget)))
gdk_window_set_cursor(window, cursor); isBusyOrGlobalCursor = true;
} }
} }
if (window && cursor == NULL && m_wxwindow == NULL) GdkCursor* cursor = NULL;
if (!isBusyOrGlobalCursor)
cursor = m_cursor.GetCursor();
GdkWindow* window = NULL;
if (cursor || isBusyOrGlobalCursor || !isRealize)
{
wxArrayGdkWindows windows;
window = GTKGetWindow(windows);
if (window)
gdk_window_set_cursor(window, cursor);
else
{
for (size_t i = windows.size(); i--;)
{
window = windows[i];
if (window)
gdk_window_set_cursor(window, cursor);
}
}
}
if (window && cursor == NULL && m_wxwindow == NULL && !isBusyOrGlobalCursor && !isRealize)
{ {
void* data; void* data;
gdk_window_get_user_data(window, &data); gdk_window_get_user_data(window, &data);