Bug 192036 - Shell.forceActive doesn't raise a window above all other windows
Summary: Shell.forceActive doesn't raise a window above all other windows
Status: REOPENED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.2.2   Edit
Hardware: PC All
: P3 normal with 3 votes (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: usability
Depends on:
Blocks:
 
Reported: 2007-06-11 16:13 EDT by Mark Siegel CLA
Modified: 2022-02-24 08:29 EST (History)
9 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Siegel CLA 2007-06-11 16:13:56 EDT
Using either Shell.forceActive or Shell.setActive doesn't consistently raise the shell above all other applications' windows.  The below snippet open a shell and calls forceActive on it every 5 seconds.  If you run the application and place another window on top (I used a Windows Explorer window), the SWT shell will not raise above that window.  Instead the shell's entry in the task bar will flash.

When I use setActive instead of forceActive, the shell will raise above the Windows Explorer window once.  But if I put the Windows Explorer window back on top, the setActive call will not raise the shell again.

public class FocusTest
{
    public static void main (String [] args)
    {
        final Display display = new Display ();
        final Shell shell = new Shell (display);

        shell.open ();

        Timer t = new Timer ();
        TimerTask task = new TimerTask ()
        {
            @Override
            public void run ()
            {
                display.asyncExec (new Runnable ()
                {
                    public void run ()
                    {
                        shell.forceActive ();
                    }
                });
            }
        };

        int time = 5000;
        t.scheduleAtFixedRate (task, 0, time);

        while (!shell.isDisposed ())
        {
            if (!display.readAndDispatch ())
                display.sleep ();
        }

        t.cancel ();
        display.dispose ();
    }
}

System information:
OS : Win XP Pro
Java : jdk1.5.0_07
SWT : 3.2.2.v3236b
Comment 1 Steve Northover CLA 2007-06-13 10:16:52 EDT
Shell.forceActive() makes the Windows API call SetForegroundWindow() (http://msdn2.microsoft.com/en-us/library/ms633539.aspx).  This call has all sorts of restrictions every application must live with.

I'm not sure that there's much we can do about this, other that try to figure out ways to outfox SetForegroundWindow().  I'm leaning towards WONTFIX.
Comment 2 Roger Pack CLA 2010-02-23 12:15:20 EST
appears from (a link at the bottom of) the msdn link that what you need to do is something like this C code (basically, if you're not the foreground window, temporarily attach to it via AttachThreadInput, then unattach.

Doesn't look impossible...

HWND __LINKAGE_WMD __stdcall ForceForegroundWindow(HWND hTo)
  {
   if (!hTo) return(NULL);
   HWND hFrom=GetForegroundWindow();
   if (!hFrom) { SetForegroundWindow(hTo); return(NULL); }
   if (hTo==hFrom) return(NULL);
   DWORD pid=GetWindowThreadProcessId(hFrom,0);
   if (_threadid==pid) { SetForegroundWindow(hTo); return(hFrom); }
   if (pid)
    {
     if (!AttachThreadInput(_threadid,pid,true)) return(NULL);
     SetForegroundWindow(hTo);
     AttachThreadInput(_threadid,pid,false);
    }
   return(hFrom);
  }
Comment 3 Roger Pack CLA 2010-02-23 19:02:20 EST
appears from experimentation that sometimes (with the work around), it brings the window forward, but only to just "behind" the active window.

To actually get it to come to the front you need to run the code, then an additional setActive afterwards (not quite sure why forceActive doesn't run one already, anyway).

http://stackoverflow.com/questions/2315560/how-do-you-force-a-java-swt-program-to-move-itself-to-the-foreground
Comment 4 Alois Geith CLA 2010-03-11 08:12:26 EST
based on Rogers C Code i just wrote the following _workaround_ 

  public void forceActive(Shell shell) {
    int hFrom = OS.GetForegroundWindow();

    if (hFrom <= 0) {
      OS.SetForegroundWindow(shell.handle);
      return;
    }

    if (shell.handle == hFrom) {
      return;
    }

    int pid = OS.GetWindowThreadProcessId(hFrom, null);
    int _threadid = OS.GetWindowThreadProcessId(shell.handle, null);

    if (_threadid == pid) {
      OS.SetForegroundWindow(shell.handle);
      return;
    }

    if (pid > 0) {
      if ( !OS.AttachThreadInput(_threadid, pid, true)) {
        return;
      }
      OS.SetForegroundWindow(shell.handle);
      OS.AttachThreadInput(_threadid, pid, false);
    }

    OS.BringWindowToTop(shell.handle);
    OS.UpdateWindow(shell.handle);
    OS.SetActiveWindow(shell.handle);
  }

as long as there is no solution to the force focus issue this workaround maybe helps. 

!!but pls keep in mind that in this workaround we use an API which is marked as "Discouraged access"!!

Alois
Comment 5 Felipe Heidrich CLA 2010-03-11 09:18:52 EST
(In reply to comment #4)
> as long as there is no solution to the force focus issue this workaround maybe
> helps. 

What is really the problem you are trying to fix ? What is this force focus issue ?


> !!but pls keep in mind that in this workaround we use an API which is marked as
> "Discouraged access"!!

Personally I rather not fix this bug. There is a good reason SetForegroundWindow() doesnt work all the time: forcing popup windows are bad design (they are really annoying).

Would something like this Bug 304922 work you ?
Comment 6 Alois Geith CLA 2010-03-11 11:05:32 EST
like roger i wanted to solve the issue that forceActive doesn't bring a shell to the front (at least not always - often the window just flashes in the taskbar)

i understand the problem with popups and agree that one should try to avoid to use  this functionality but there are also cases were this behaviour is a requirement!

for instance the project i currently work on has this requirement. they want to replace an old crm system gradually, some tasks are handled by an eclipse rcp application, others by the old system. another non functional requirement is to save time (money). so they don't accept that the user has to switch applications by using the mouse (they one to save every single click they can) ....

Alois
Comment 7 Olof Jonsson CLA 2014-09-18 02:45:02 EDT
Is this not fixed yet? I'm using eclipse 3.7 on Windows 7 and still have the same problem. 

When window is minimized it is brought to the top by the following code

shell().setMinimized(false);
shell.forceActive();


but not when otherwise. The code Aloise provided works though but is just workaround.

/Olof
Comment 8 Eclipse Genie CLA 2020-04-27 16:30:59 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 9 Lars Vogel CLA 2021-09-23 04:23:15 EDT
Can this be fixed? It would be nice to be able to put a shell to foreground without any hacks.
Comment 10 Thomas Singer CLA 2022-02-23 15:00:09 EST
Strange, we have the problem, that our SWT application erratically brings itself into foreground on Windows 10 if a control is focused using setFocus() while we are working in another application (e.g. IDE saving a file in a watched directory).
Comment 11 Rolf Theunissen CLA 2022-02-24 03:37:50 EST
(In reply to Thomas Singer from comment #10)
> Strange, we have the problem, that our SWT application erratically brings
> itself into foreground on Windows 10 if a control is focused using
> setFocus() while we are working in another application (e.g. IDE saving a
> file in a watched directory).

The difference here is that in your case the Shells are all connected to the same thread, while in this bug the Shells are connected to different threads. In that case, there must be a connection to the other thread.

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setfocus
"""By using the AttachThreadInput function, a thread can attach its input processing to another thread. This allows a thread to call SetFocus to set the keyboard focus to a window attached to another thread's message queue."""
Comment 12 Thomas Singer CLA 2022-02-24 05:52:18 EST
How is it possible with SWT to operate on controls/shells from different threads? Until now I had the impression that all operations need to be performed in the (single) GUI thread (usually the one where `main` was started).
Comment 13 Rolf Theunissen CLA 2022-02-24 07:46:55 EST
(In reply to Thomas Singer from comment #12)
> How is it possible with SWT to operate on controls/shells from different
> threads? Until now I had the impression that all operations need to be
> performed in the (single) GUI thread (usually the one where `main` was
> started).

There is a single SWT/UI thread for each process, e.g., when you fire up two Eclipse instances there are two UI threads, one in each process. Every independent process has its own UI thread.