Opened 3 months ago

Closed 2 months ago

#15801 closed defect (fixed)

The cursor is not inherited in wxGTK

Reported by: jbbbms Owned by: pcor
Priority: normal Milestone: 3.0.1
Component: wxGTK Version: dev-latest
Keywords: wxWindow::SetCursor, wxGTK Cc: dghart@…
Blocked By: Blocking:
Patch: no

Description

According to the document, child windows will have the same cursor, but they don't. It does happen in wxMSW, but not in wxGTK, no matter the wxGTK is based on GTK+2 or GTK+3. Below is a demo that reconstructs the bugs. Thanks.

Attachments (2)

buggy.cpp download (786 bytes) - added by jbbbms 3 months ago.
In wxGTK, child windows don't inherit the cursor.
minimal.diff download (1.8 KB) - added by dghart 2 months ago.

Download all attachments as: .zip

Change History (22)

Changed 3 months ago by jbbbms

In wxGTK, child windows don't inherit the cursor.

comment:1 Changed 3 months ago by jbbbms

  • Keywords wxWindow::SetCursor added; SetCursor removed

comment:2 follow-up: Changed 3 months ago by vadz

  • Priority changed from normal to low
  • Status changed from new to confirmed
  • Summary changed from The cursor is not inherited in wxGTK. to The cursor is not inherited in wxGTK if the child window is created after setting it

I think calling SetCursor() after creating the child window should work, i.e. SetCursor() does change the cursor recursively -- but child windows don't inherit the parent cursor when they're being created. They should, and this should be relatively simple to fix...

comment:3 in reply to: ↑ 2 Changed 3 months ago by jbbbms

Replying to vadz:

I think calling SetCursor() after creating the child window should work, i.e. SetCursor() does change the cursor recursively

It doesn't. If we move the line frame->SetCursor(*wxCROSS_CURSOR); in the buggy.cpp, the attached file above, to somewhere after the first child's SetCursor, the first child will still use its own cursor, not the cursor from its parent. That is, the SetCursor doesn't change anything at all, except the cursor of the calling control itself.

comment:4 Changed 3 months ago by vadz

  • Priority changed from low to normal
  • Summary changed from The cursor is not inherited in wxGTK if the child window is created after setting it to Setting the cursor for wxFrame doesn't work in wxGTK

Actually for me setting the cursor doesn't even seem to work for the frame itself, as shown by this patch:

  • samples/minimal/minimal.cpp

    diff --git a/samples/minimal/minimal.cpp b/samples/minimal/minimal.cpp
    index a78e462..461315e 100644
    a b bool MyApp::OnInit() 
    172172    CreateStatusBar(2); 
    173173    SetStatusText("Welcome to wxWidgets!"); 
    174174#endif // wxUSE_STATUSBAR 
     175 
     176    SetCursor(*wxCROSS_CURSOR); 
     177    new wxStaticText(this, wxID_ANY, "Just a label", wxPoint(5, 5)); 
     178 
     179    wxWindow* w = new wxWindow(this, wxID_ANY, wxPoint(5, 20), wxSize(200, 100)); 
     180    w->SetBackgroundColour(*wxRED); 
    175181} 
    176182 
    177183 

So something is definitely broken here... FWIW setting the cursor on a panel doesn't work neither.

comment:5 Changed 3 months ago by pcor

  • Owner set to pcor
  • Status changed from confirmed to accepted
  • Summary changed from Setting the cursor for wxFrame doesn't work in wxGTK to The cursor is not inherited in wxGTK

The original title is correct. The cursor is not inherited in wxGTK (except for "no window" widgets, such as wxStaticText). It has nothing to do with wxFrame or whether child windows are created before or after the cursor is set. Reading the ancient comments at the top of src/gtk/window.cpp, and digging through the file histories, leads me to believe that the current behavior is intentional, and has been that way forever.

And, just for completeness, wxBusyCursor also appears to be a borked-up mess.

comment:6 Changed 3 months ago by vadz

I'm surprised, I thought it was such a mess because Robert had to implement the cursor inheritance. I must be misremembering then...

What is certain, however, is that cursor inheritance does work under MSW.

The bust cursor is still a mess even there though :-(

comment:7 follow-up: Changed 3 months ago by PC

  • Resolution set to fixed
  • Status changed from accepted to closed

(In [75690]) Fix cursor inheritance and busy cursor/global cursor, closes #15801

comment:8 follow-up: Changed 3 months ago by dghart

  • Cc dghart@… added
  • Resolution fixed deleted
  • Status changed from closed to reopened
  • Version changed from 3.0.0 to dev-latest

I'm afraid this commit has caused a problem, probably for wxAui managed windows. This is very obvious in CodeLite, but can be seen in parts of the auidemo sample: change to the 'wxPanel' notebook page, then move the cursor from the bottom text pane into the notebook page. The cursor will stick with double-arrow sizing appearance it acquired as it crossed between panes until it leaves the panel. This usually also happens when moving from the left tree pane onto the tabs of the notebook.

I can't reproduce this in any of the other samples. Annoyingly, I also can't reproduce it by hacking segments of auidemo into 'minimal', though I'll attached a diff of that in case you want to try harder (it won't link using 'minimal's makefile).

comment:9 in reply to: ↑ 7 Changed 3 months ago by R.U.10

Replying to PC:

Since [75690] I can't compile on RHEL 5.8 with GTK 2.10.4:

./src/gtk/cursor.cpp: In function ‘void clearCursors(GdkWindow*)’:
./src/gtk/cursor.cpp:356:53: error: ‘gdk_window_get_cursor’ was not declared in this scope
     GdkCursor* cursor = gdk_window_get_cursor(window);

comment:10 Changed 3 months ago by vadz

  • Milestone set to 3.1.0

Hmm, gdk_window_get_cursor() is 2.18+, but it just returns GdkWindowObject::cursor. Could we just access it directly for the older versions?

comment:11 in reply to: ↑ 8 Changed 2 months ago by pcor

  • Milestone changed from 3.1.0 to 3.0.1

Replying to dghart:

I'm afraid this commit has caused a problem, probably for wxAui managed windows.

This has something to do with EVT_SET_CURSOR routing. On Windows, some default mechanism is getting set-cursor events aimed at wxAuiTabCtrl routed to wxAuiManager. On wxGTK, the event only goes to wxAuiTabCtrl.

comment:12 follow-up: Changed 2 months ago by vadz

WM_SETCURSOR bubbles up by default under Windows, quoting MSDN:

The DefWindowProc function passes the WM_SETCURSOR message to a parent window before processing. If the parent window returns TRUE, further processing is halted. Passing the message to a window's parent window gives the parent window control over the cursor's setting in a child window. The DefWindowProc function also uses this message to set the cursor to an arrow if it is not in the client area, or to the registered class cursor if it is in the client area.

This behaviour seems useful, so I think we should do the same in wxGTK.

comment:13 Changed 2 months ago by PC

(In [75807]) 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

comment:14 Changed 2 months ago by PC

(In [75821]) Fix wxSetCursorEvent handling
For compatibility with wxMSW, send event up the parent chain.
Properly handle setting the cursor for a wxSetCursorEvent, and don't overwrite the window cursor.
see #15801

comment:15 Changed 2 months ago by dghart

I confirm that this has fixed the issue for me. Thanks!

comment:16 Changed 2 months ago by pcor

  • Resolution set to fixed
  • Status changed from reopened to closed

Thanks for confirming.

Changed 2 months ago by dghart

comment:17 Changed 2 months ago by dghart

  • Resolution fixed deleted
  • Status changed from closed to reopened

I'm sorry to keep reopening this, but another bug has been pointed out on the CodeLite forum. This time it's wxStyledTextCtrls inside wxAui managed windows. A wxSTC, like a wxTextCtrl, normally has a text-cursor. However since 9d0d2b7e98 this doesn't happen; it has a standard arrow one instead. This can be seen in the replacement minimal.diff (which needs additional aui and stc linkage).

comment:18 in reply to: ↑ 12 Changed 2 months ago by pcor

Replying to vadz:

WM_SETCURSOR bubbles up by default under Windows

Yeah, except if there is a window in the chain with a wxCursor set, wxMSW stops there. Just lovely. And so well documented. Agghhh.

comment:19 Changed 2 months ago by vadz

How else could it work? If we need to set the cursor for a particular window we have to handle WM_SETCURSOR in it, otherwise where would its cursor come from? I mean, I guess we could let it always propagate to the very top and then find out the deepest window with non default cursor from the TLW handler but this would be more complicated and less efficient (and efficiency does matter here as this code is executed for each mouse pointer movement).

Sorry if I was unclear but "bubbles up" was supposed to mean "bubbles up until somebody handles it", of course...

comment:20 Changed 2 months ago by PC

  • Resolution set to fixed
  • Status changed from reopened to closed

(In [75888]) mimic wxMSW wxSetCursorEvent propagation behavior, closes #15801

Note: See TracTickets for help on using tickets.