Author Topic: [SOLVED] How to "unfocus" a Form?  (Read 1253 times)

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
[SOLVED] How to "unfocus" a Form?
« on: September 30, 2026, 04:30:54 pm »
Let's say I have a Form which has the Focus. How can I "unfocus" this Form?

I found only the following way, which "does the job", but of course 1) it flickers and 2) it is very cumbersome:

Code: Pascal  [Select][+][-]
  1. Form1.WindowState:=wsMinimized; // moves the focus back to the last program who had it
  2. ... need to wait some time and call Application.ProcessMessages a few times
  3. Form1.WindowState:=wsNormal; // shows the Form again, which now has NOT the Focus

Does someone know a better way? Without flicker and less cumbersome?
I want a solution for Linux (more important) and Windows (less important) or 2 different solutions.

Currently it would be enough, if it would work on Windows 7 and Linux Ubuntu 24.04 with KDE-Plasma and GTK2. Of course, a more general solution would be "better", but if this would make things too complicate, it would not be worth enough for me.

Thanks in advance.
« Last Edit: October 09, 2026, 05:39:10 pm by Hartmut »

Ten_Mile_Hike

  • Full Member
  • ***
  • Posts: 154
Re: How to "unfocus" a Form?
« Reply #1 on: September 30, 2026, 07:09:17 pm »
Give focus to the Windows Desktop

Code: Pascal  [Select][+][-]
  1. uses Windows;
  2.  SetForegroundWindow(FindWindow('Progman', nil));
« Last Edit: September 30, 2026, 08:35:51 pm by Ten_Mile_Hike »
When any government, or any church for that matter, undertakes to say to its subjects, This you may not read, this you
must not see, this you are forbidden to know, the end result is tyranny and oppression no matter how holy the motives.

Robert A. Heinlein

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
Re: How to "unfocus" a Form?
« Reply #2 on: October 01, 2026, 04:17:11 pm »
Thanks for this idea Ten_Mile_Hike, indeed it moves the Focus to the Desktop. Unfortunately this is not what I want (I did not explain my goal clearly enough, sorry).

I want, that the Focus goes back to the program, which had the Focus, before my Form was made visible, as it is done by my cumbersome minimizing/normalizing code (see above).

I want this feature for a program, which runs the most time in background, where it's Form is not visible. If certain circumstances are met, the Form is made visible to show some infos (and it has some buttons for some actions). But if this Form, when coming up, "steals" the Focus from another program, where you are e.g. just typing in text, then this disturbs (and some part of what you typed is lost, especially if your eyes are mostly on the keyboard).

I hope for a solution for Linux (more important) and Windows (less important) or 2 different solutions.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12760
  • Debugger - SynEdit - and more
    • wiki
Re: How to "unfocus" a Form?
« Reply #3 on: October 01, 2026, 05:13:12 pm »
Well get the active application before you show, then set it back? (or active system wide form?) => not checked how....


Or you may have to "hack" into how to show the form.
I don't know if you can show the form without focus at first via the LCL, but the Windows msdn methods for that might be able to do that. Then you can just create the handle, and call the Win kernel to show it.
Though that may then cause subsequent issues on the LCL not knowing that the form is visible.

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
Re: How to "unfocus" a Form?
« Reply #4 on: October 01, 2026, 06:01:46 pm »
Well get the active application before you show, then set it back? (or active system wide form?) => not checked how....

Thanks for your reply Martin. I'm not sure if I understand corectly what you mean... Do you mean this?
 - first find out which application currently has the Focus?
 - then show my Form
 - then move the Focus back to the previous application?
I have no idea if and how this could be achieved. It should be aware, that an application can have more then 1 Form currently visible and that an application may run multiple instances at the same time.
As said, I want a solution for Linux (more important) and for Windows (less important).
If someone knows, how this could be achieved, I would be interested, but if it makes too much effort, it would not be worth enough for me.

Quote
Or you may have to "hack" into how to show the form.
I don't know if you can show the form without focus at first via the LCL, but the Windows msdn methods for that might be able to do that. Then you can just create the handle, and call the Win kernel to show it.
Though that may then cause subsequent issues on the LCL not knowing that the form is visible.

A Windows-only-solution via msdn-methods, especially if that may then cause subsequent issues on the LCL not knowing that the form is visible, sounds for me not being worth enough the effort.

But *if* it is possible via the LCL, to show the form without focus at first, this sounds very interesting.
If someone knows, how this could be achieved, I would be very interested.

440bx

  • Hero Member
  • *****
  • Posts: 6619
Re: How to "unfocus" a Form?
« Reply #5 on: October 01, 2026, 06:43:29 pm »
Just a thought...  I haven't tried this but, it may work.

Disable the window then immediately re-enable it.  There should be no flicker and disabling the window _might_ cause the O/S to switch the focus to a different window and, hopefully re-enabling it won't cause the O/S to switch the focus back to it.

I believe it is simple enough to test that it's worth a try.  Hopefully that will do the trick for you and, it probably is O/S independent.

HTH.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
Re: How to "unfocus" a Form?
« Reply #6 on: October 01, 2026, 07:24:02 pm »
Thank you 440bx for this suggestion. Unfortunately it did not work. I tried Hide + Show, Visible:=false + Visible:=true and Enabled:=false + Enabled:=true, all 3 on Windows and Linux. Always the Focus stayed on my Form.

I'm optimistic that the OS is able to do what I want (move the Focus back to the program who had it before).
The questions are:
 - is this feature callable from outside the OS (and how)?
 - is the LCL able to "show" a Form without forcing the Focus to that Form?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12760
  • Debugger - SynEdit - and more
    • wiki
Re: How to "unfocus" a Form?
« Reply #7 on: October 01, 2026, 07:31:53 pm »

 - first find out which application currently has the Focus?
 - then show my Form
 - then move the Focus back to the previous application?
I have no idea if and how this could be achieved. It should be aware, that an application can have more then 1 Form currently visible and that an application may run multiple instances at the same time.

As said, I want a solution for Linux (more important) and for Windows (less important).
If someone knows, how this could be achieved, I would be interested, but if it makes too much effort, it would not be worth enough for me.


Probably: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow

Sorry, I missed the Linux bit somehow. Don't know how to do it there. And it may even differ (and/or not be possible) depending on WindowManager...)

---------
In the end, if there is on other answer, you can dig down through the LCL, find the code for each WS (gtk2/3/qt/win) that actually shows the window. Find the call to the OS, and google the API for that call, and see if it can be instructed to skip the focus. And then patch the LCL/WS.



H₂SO₄

  • Hero Member
  • *****
  • Posts: 511
Re: How to "unfocus" a Form?
« Reply #8 on: October 02, 2026, 07:07:40 am »
I want this feature for a program, which runs the most time in background, where it's Form is not visible. If certain circumstances are met, the Form is made visible to show some infos (and it has some buttons for some actions). But if this Form, when coming up, "steals" the Focus from another program, where you are e.g. just typing in text, then this disturbs (and some part of what you typed is lost, especially if your eyes are mostly on the keyboard).

I'm smelling another XY problem here... is this your actual goal? To prevent your application from stealing focus when it (re)activates itself?

Because if it is, then I've got a partial solution for you  :)  (Windows-only unfortunately):

Code: Pascal  [Select][+][-]
  1. {$ifdef WINDOWS}
  2.   ShowWindow(Form.Handle, SW_SHOWNOACTIVATE); // Makes the form visible without stealing focus
  3. {$endif}
  4.  
  5. Form.Visible := True; // Synchronizes LCL state with WM state
  6. Form.Update();        // Required in my use case (splash screen), but it's possible that your form doesn't need this

Instead of manually juggling focus around, this code simply avoids stealing focus in the first place - much simpler.

paweld

  • Hero Member
  • *****
  • Posts: 1770
Re: How to "unfocus" a Form?
« Reply #9 on: October 02, 2026, 07:29:54 am »
Linux and Windows:
Code: Pascal  [Select][+][-]
  1. uses
  2.   {$IFDEF WINDOWS}Windows{$ELSE}XLib, X{$ENDIF};
  3.  
  4. var
  5.   {$IFDEF WINDOWS}
  6.   FPreviousWindow: HWND;
  7.   {$ELSE}
  8.   FPreviousWindow: TWindow;
  9.   FPreviousRevert: Integer;
  10.   FDisplay: PDisplay;
  11.   {$ENDIF}
  12.  
  13. procedure SaveFocus;
  14. begin
  15.   {$IFDEF WINDOWS}
  16.   FPreviousWindow := GetForegroundWindow;
  17.   {$ELSE}
  18.   FDisplay := XOpenDisplay(nil);
  19.   if FDisplay <> nil then
  20.     XGetInputFocus(FDisplay, @FPreviousWindow, @FPreviousRevert);
  21.   {$ENDIF}
  22. end;
  23.  
  24. procedure RestoreFocus;
  25. begin
  26.   {$IFDEF WINDOWS}
  27.   SetForegroundWindow(FPreviousWindow);
  28.   {$ELSE}
  29.   if (FDisplay <> nil) and (FPreviousWindow <> 0) then
  30.   begin
  31.     XSetInputFocus(FDisplay, FPreviousWindow,
  32.                    FPreviousRevert, CurrentTime);
  33.     XFlush(FDisplay);
  34.   end;
  35.   {$ENDIF}
  36. end;
And at the beginning of the form's OnCreate event, you call SaveFocus, and in the destination event call RestoreFocus

Tested on Linux Mint (Cinnamon X11) and Windows 10.
Best regards / Pozdrawiam
paweld

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
Re: How to "unfocus" a Form?
« Reply #10 on: October 02, 2026, 01:30:36 pm »
Thanks to all for your new posts.

Probably: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow
I have good news: on Windows this works now! Thanks a lot Martin.

There was some disadvantage, that when the Focus is moved back to the program, who had it before, that then this other program is also moved to the foreground, so it can cover "my Form" partly or completely.

The only way I could find to prevent this, is to use 'FormStyle:=fsSystemStayOnTop' before 'SetForegroundWindow'.

But I had massive problems, because this only worked, when I set 'FormStyle:=fsSystemStayOnTop' *permanently* (but that's not what I want).
 - all what I tried to set again 'FormStyle:=fsNormal' "later" moved the other program in the foreground and could cover my Form
 - all what I tried to set 'FormStyle:=fsStayOnTop' "later" did nothing, that means, that my Form stayed permanently with 'fsSystemStayOnTop' over all other programs.

After trying "millions" of variations for some hours the problem suddenly disapeared. Now it works to set 'FormStyle:=fsNormal' after 'SetForegroundWindow' (and it works also after a restart of Windows). Have absolute no explanation for that.

If this issue does not occur again I have a good solution for Windows :-))



To prevent your application from stealing focus when it (re)activates itself? Because if it is, then I've got a partial solution for you  :)  (Windows-only unfortunately):
Code: Pascal  [Select][+][-]
  1. {$ifdef WINDOWS}
  2.   ShowWindow(Form.Handle, SW_SHOWNOACTIVATE); // Makes the form visible without stealing focus
  3. {$endif}  
  4. Form.Visible := True; // Synchronizes LCL state with WM state
  5. Form.Update();        // Required in my use case (splash screen), but it's possible that your form doesn't need this
I tried your suggestion (it reads as it should work), but unfortunately my Form always has the Focus when it is made visible this way.
Without 'Update' command there is no difference.
Without 'Visible:=True' the Form stays invisible.
I tested in Win7 32bit with Lazarus 3.6.0 and 2.0.10.



Linux and Windows:
...
And at the beginning of the form's OnCreate event, you call SaveFocus, and in the destination event call RestoreFocus
Tested on Linux Mint (Cinnamon X11) and Windows 10.
The Windows part is the same as from Martin, I got it to work.
The Linux part I will test as soon I find some time and will report after.

BTW: on Linux I use WindowManager 'X11' (forgot to mention that).

cdbc

  • Hero Member
  • *****
  • Posts: 2964
    • http://www.cdbc.dk
Re: How to "unfocus" a Form?
« Reply #11 on: October 02, 2026, 02:02:36 pm »
Hi
Quote
BTW: on Linux I use WindowManager 'X11' (forgot to mention that).
In that case, use Pawel's code from his post above.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
Re: How to "unfocus" a Form?
« Reply #12 on: October 02, 2026, 05:23:27 pm »
Linux and Windows:
...
And at the beginning of the form's OnCreate event, you call SaveFocus, and in the destination event call RestoreFocus
Tested on Linux Mint (Cinnamon X11) and Windows 10.

I'm fighting with the code of paweld from reply #9: somtimes it works (the focus is moved back to the program who had it before), sometimes it works not (my Form has the Focus). Sometimes my Form appears in the foreground, sometimes it is partly covered by other programs. Sometimes the 1st appearence of my Form can be different from all later ones.

1st of all I want to clarify the result codes of XSetInputFocus() and XFlush(). In my case both are always '1', regardless whether it works or not. What does '1' mean?

I found only "thousands" of pages like https://linux.die.net/man/3/xsetinputfocus which only mentions "XSetInputFocus can generate BadMatch, BadValue, and BadWindow errors", but of course does *not* tell their values and does *not* tell which value means "success". I "love" such documentation :-(((

The only thing I found in a reliable time is <installdir>/fpcsrc/packages/x11/src/x.pp which from line 219 on contains:
   Success = 0;
   BadRequest = 1;
   BadValue = 2;
   BadWindow = 3;
   BadPixmap = 4;
   BadAtom = 5;
   BadCursor = 6;
   BadFont = 7;
   BadMatch = 8;
*If* this list would be suitable, then '1' would mean 'BadRequest'.
But I get this result also, if it works!
Can please someone explain to me, what '1' really means and which value should come at success?
For XSetInputFocus() and XFlush()?
And if someone knows a better documentation page, which answers all this, this would be very welcome too.

paweld

  • Hero Member
  • *****
  • Posts: 1770
Re: How to "unfocus" a Form?
« Reply #13 on: October 02, 2026, 06:40:48 pm »
Whether calling the function causes an error or not does not depend on the value it returns. You have to catch that error yourself by set the handler.
Code: Pascal  [Select][+][-]
  1. uses
  2.   {$IFDEF WINDOWS}Windows{$ELSE}XLib, X{$ENDIF};
  3.  
  4. var
  5.   {$IFDEF WINDOWS}
  6.   FPreviousWindow: HWND;
  7.   {$ELSE}
  8.   FPreviousWindow: TWindow;
  9.   FPreviousRevert: Integer;
  10.   FDisplay: PDisplay;
  11.   {$ENDIF}
  12.  
  13. {$IFDEF LINUX}
  14. function XErrorHandler(display: PDisplay; event: PXErrorEvent): Integer; cdecl;
  15. begin
  16.   WriteLn('X - error code: ', event^.error_code, '; request code: ', event^.request_code);
  17.   // error code: https://xorg.freedesktop.org/archive/X11R7.7/doc/xproto/x11protocol.html#Encoding::Errors
  18.   //   1 - BadRequest
  19.   //   2 - BadValue
  20.   //   3 - BadWindow
  21.   // request code: https://xorg.freedesktop.org/archive/X11R7.7/doc/xproto/x11protocol.html#Encoding::Requests
  22.   //   42 - SetInputFocus
  23.   Result := 0;
  24. end;
  25. {$ENDIF}
  26.  
  27. procedure SaveFocus;
  28. begin
  29.   {$IFDEF WINDOWS}
  30.   FPreviousWindow := GetForegroundWindow;
  31.   {$ELSE}
  32.   FDisplay := XOpenDisplay(nil);
  33.   if FDisplay <> nil then
  34.     XGetInputFocus(FDisplay, @FPreviousWindow, @FPreviousRevert);
  35.   {$ENDIF}
  36. end;
  37.  
  38. procedure RestoreFocus;
  39. begin
  40.   {$IFDEF WINDOWS}
  41.   SetForegroundWindow(FPreviousWindow);
  42.   {$ELSE}
  43.   if (FDisplay <> nil) and (FPreviousWindow <> 0) then
  44.   begin
  45.     XSetErrorHandler(@XErrorHandler);
  46.     XSetInputFocus(FDisplay, FPreviousWindow, FPreviousRevert, CurrentTime);
  47.     XSync(FDisplay, False);
  48.     XFlush(FDisplay);
  49.   end;
  50.   {$ENDIF}
  51. end;
Best regards / Pozdrawiam
paweld

Hartmut

  • Hero Member
  • *****
  • Posts: 1188
Re: How to "unfocus" a Form?
« Reply #14 on: October 02, 2026, 07:33:06 pm »
Thank you very much paweld for this improvement to your code.

Even in the cases, where the Focus is *not* moved back to the program, who had it before (which means, the Focus stays on my Form), 'XErrorHandler' is *not* called. In this case I have e.g. the following values:
FDisplay=20FB5E40 (pointer in hex)
FPreviousWindow=88080397
FPreviousRevert=1


But I checked, that 'XErrorHandler' is called, when I manipulate 'FPreviousWindow:=12345', so it works generally.

Must stop for today, will continue tomorrow and if I don't get it, post some code.
As said, I'm on Linux Ubuntu 24.04 64bit with KDE-Plasma and GTK2 and X11 WindowManager with Lazarus 3.4.0 and 2.0.10 (both act the same).

One last question for today: I assume that 'XSetErrorHandler(@XErrorHandler)' installs an error handler. Would it be a good idea to "deactivate" this at the end of procedure RestoreFocus? E.g. by XSetErrorHandler(nil) ?

 

TinyPortal © 2005-2018