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:
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
@@ -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());
|
||||||
|
@@ -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)))
|
||||||
{
|
{
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user