Recent

Author Topic: Gtk2 busy cursor for blocking code  (Read 1055 times)

maxerist

  • New Member
  • *
  • Posts: 20
Gtk2 busy cursor for blocking code
« on: December 02, 2022, 02:06:40 pm »
Hi,

In my code originating from Windows there are plenty of places where conceptually the code that potentially can block the interaction for a sensitive time is wrapped with Screen.Cursor:=crHourGlass/Screen.Cursor:=crDefault. In Windows this always worked probably due to the historical nature of the cursor handling in gdi that is not dependent on the controls and message queues. In Linux/Gtk2 I see that direct equivalent is not always works as expected.

The symptoms are:
  • For direct blocking code without interaction with gtk (Sleep, while timertick > ...) the cursor never changes during the blocking period. I see the arrow all the time.
  • If I change the cursor and postpone the blocking code with a message sent to myself, everything is ok.
  • If I directly call update of some of the controls at the form (it seems it's the one I just clicked or direct window ancestors) then everything is also ok.
  • Probably in other places where I can not directly explain specifics about the code, there might be some operations involving indirect communication with gtk and the cursor partially works so I sometimes see the hourglass equivalent but there are delays before it actually appears.

Is this something that confirmed and somehow maybe documented? I tried to google with gdk_window_set_cursor  and related terms, just nothing. And about workaround I mentioned (updating some control). This method is not something I can implement without potentially bad consequences. I tried to always make a TForm.Update call when the busy period is starting and probably the cursor problem was gone, but I faced other non-desirable drawing artifacts

Thanks

AlexTP

  • Hero Member
  • *****
  • Posts: 2383
    • UVviewsoft
Re: Gtk2 busy cursor for blocking code
« Reply #1 on: December 02, 2022, 02:19:33 pm »
Maybe new methods will help, in TScreen.

    procedure BeginTempCursor(const aCursor: TCursor);
    procedure EndTempCursor(const aCursor: TCursor);
    procedure BeginWaitCursor;
    procedure EndWaitCursor;
    procedure BeginScreenCursor;
    procedure EndScreenCursor;

if not, still better to use them, and ask for a fix for them for gtk2. Maybe only missed thing is APplication.ProcessMessages.

maxerist

  • New Member
  • *
  • Posts: 20
Re: Gtk2 busy cursor for blocking code
« Reply #2 on: December 02, 2022, 07:40:28 pm »
Maybe new methods will help, in TScreen.

    procedure BeginTempCursor(const aCursor: TCursor);
    procedure EndTempCursor(const aCursor: TCursor);
.....
if not, still better to use them, and ask for a fix for them for gtk2. Maybe only missed thing is APplication.ProcessMessages.

Thanks, I tried BeginTempCursor, still no luck. Looking at the source, this method looks like a syntax sugar around the regular Screen.Cursor.
 
Using ProcessMessages was on my mind before. It looks like using this call after setting the cursor does the magic for a simple case. But for more complex cases it might involve unexpected message handling when there was none before. Too risky for a big project.

PeterBB

  • New Member
  • *
  • Posts: 40
Re: Gtk2 busy cursor for blocking code
« Reply #3 on: December 14, 2022, 03:24:29 pm »
Hi maxerist,

not sure if this is the same issue, but I found recently my program stopped responding to cusror changes.
I fixed it by using the form's cursor property instead of the screen's cursor.

There were some changes to cursor handling in 2.2.0


Cheers,
Peter

maxerist

  • New Member
  • *
  • Posts: 20
Re: Gtk2 busy cursor for blocking code
« Reply #4 on: December 15, 2022, 10:02:01 am »
I fixed it by using the form's cursor property instead of the screen's cursor.

Thanks, to evaluate your suggestion I did some tests.

My primary one (I should have posted it before) is this (just a button on the form, when I pressed it, the event handler)

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Screen.Cursor:=crHourGlass;
  4.   try
  5.     Sleep(10000);
  6.   finally
  7.      Screen.Cursor:=crDefault;
  8.   end;
  9. end;
  10.  
This test works as expected on Windows/Delphi and Windows/Lazarus. So the cursor is instantly the busy one and for the following 10 seconds I can hover over the form and the button and see no other active cursor.

This test also reveals the issue of my original post (no busy cursor with Linux, Lazarus 2.2.2, fpc 3.2.2, gtk2 (version 2.24.33-7.el9)), VirtualBox machine (another guess as of time of this writing is that the problem might arise with cursor integration when dealing with virtual guests)

When I switch the cursor assignment to Cursor:=... instead of Screen.Cursor:= (so effectively using your suggestion) I see no expected behavior on all three tests (Windows and Linux), no busy cursor while hovering over both the form and the button. So probably your circumstances are little different from the ones with my test. Can you reproduce the expected cursor working with this simple test on your configuration?


Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Gtk2 busy cursor for blocking code
« Reply #5 on: December 15, 2022, 10:14:08 am »
The windows code seems wrong: that keeps the hourglass also outside of the form and that is a design flaw.
Both Windows and Gtk2 code should change/update the cursor through te form, not the screen.
That also keeps it compatible.
Specialize a type, not a var.

maxerist

  • New Member
  • *
  • Posts: 20
Re: Gtk2 busy cursor for blocking code
« Reply #6 on: December 15, 2022, 10:32:43 am »
The windows code seems wrong: that keeps the hourglass also outside of the form and that is a design flaw.
Both Windows and Gtk2 code should change/update the cursor through te form, not the screen.
That also keeps it compatible.

As I recall Windows historically required setting the cursor with SetCursor function that was developed as a global one and in pre-Windows 95 era this indeed affected windows outside the application one. Then when the multi-threaded environment posed its own logic, naturally gdi just started sandboxing "global" cursor. Nowadays you have to do some dirty special tricks to affect cursors of other applications' windows.

PeterBB

  • New Member
  • *
  • Posts: 40
Re: Gtk2 busy cursor for blocking code
« Reply #7 on: December 15, 2022, 04:34:58 pm »
Both Windows and Gtk2 code should change/update the cursor through te form, not the screen.

As I discovered after half a day of hair pulling!  Should the docs now be updated? Maybe show TScreen.cursor as deprecated. It worked OK in the past.


Can you reproduce the expected cursor working with this simple test on your configuration?

No time, sorry.  But the code is here is you want to have a play.
https://sourceforge.net/projects/c-evo-eh/files/Source/
The cursor code is in CityTypes.pas

(I suspect a form update may be neeed for the changed cusror to show.)


Cheers,
Peter

P.S.  Same in Qt5

zeljko

  • Hero Member
  • *****
  • Posts: 1594
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Gtk2 busy cursor for blocking code
« Reply #8 on: December 15, 2022, 05:00:06 pm »
It works here (trunk lazarus) for Qt4, Qt5 and Qt6 w/o problems.

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Gtk2 busy cursor for blocking code
« Reply #9 on: December 15, 2022, 08:51:42 pm »
Both Windows and Gtk2 code should change/update the cursor through te form, not the screen.

As I discovered after half a day of hair pulling!  Should the docs now be updated? Maybe show TScreen.cursor as deprecated. It worked OK in the past.
Well, maybe, but Tscreen.cursor has its own uses.
Specialize a type, not a var.

PeterBB

  • New Member
  • *
  • Posts: 40
Re: Gtk2 busy cursor for blocking code
« Reply #10 on: December 16, 2022, 01:47:18 pm »
@Mods

Just wondering if this thread could be moved and retitled.
Issue does not seem to be specific to Linux or Gtk2


 

TinyPortal © 2005-2018