Results 1 to 14 of 14

Thread: On "there is no reliable way to activate a window"

  1. #1
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default On "there is no reliable way to activate a window"

    I have the following code:
    Qt Code:
    1. Qt::WindowFlags flags = Qt::Window;
    2. flags |= Qt::FramelessWindowHint;
    3. flags |= Qt::WindowStaysOnTopHint;
    4. setWindowFlags(flags);
    5.  
    6. //...
    7.  
    8. show();
    9. raise();
    10. activateWindow();
    11. imageLabel->setFocus(Qt::ActiveWindowFocusReason);
    To copy to clipboard, switch view to plain text mode 
    Now it does not always works on Windows, because as they said:
    since windows 2000 there is no reliable way
    to activate a window. You can flash the title bar, though. And Microsoft
    calls that a security feature ;-)
    So what happens is that when I pop up the window, it receives the keyboard focus mostly, but sometimes it doesn't, in which case the user will start to hit the keyboard like crazy since the foreground application will not receive anything (Qt::WindowStaysOnTopHint prevents him from seeing what is in the active, background window).
    So I should display a red label or something if the window is not receiving keyboard events, saying that press Alt+Tab or Click before you type. However, I don't know how to detect if it is not active.

  2. #2
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    you mean isActiveWindow()?
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  3. #3
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Quote Originally Posted by high_flyer View Post
    Theoretically, but
    Qt Code:
    1. show();
    2. raise();
    3. activateWindow();
    4. imageLabel->setFocus(Qt::ActiveWindowFocusReason);
    5. if (!isActiveWindow())
    6. abort();
    To copy to clipboard, switch view to plain text mode 
    doesn't detect whether activateWindow() failed or not. (The docs also admits that it can fail on Windows and X11.)

  4. #4
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    hmm...
    Try detecting the changed window state then with QWindowStateChangeEvent
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  5. #5
    Join Date
    Aug 2006
    Posts
    44
    Thanked 7 Times in 7 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Most UI elements already have something to indicate if they have key focus... a blinking cursor, 'selection rectangle' around button text, highlight (rollover) colors, etc. Is your application different from those?

    I've expended large amounts of time and effort on these kinds of problems in the development of a commercial package. Managing Z-plane, activation and focus in an envrionment with arbitrary windows from arbitrary threads (and in some cases, processes!) isn't trivial. It looks like you're doing 'the right thing' in your code. Even in the case of a 'topmost' window, the title bar should show 'active' or not.

    But, don't forget the 'focus-follows-mouse' scenario! :P Then, you can't simply rely on activation -- I *hate* that. And of course, in X, your user might be running who-knows-what flavor-of-the-month buggy as bat-sh*t window manager with random features and adherance to quasi-"standards" over a 300 baud modem and blame you (or Qt) for failing to operate perfectly. Go figure. Me, bitter about that kind of thing? Where'd you get that idea!?

    BTW, the reasons for the policy in Windows w.r.t. window / focus 'stealing' are actually sound -- and if you dig around in MSDN you can find ways to circumvent the policy. Consider this scenario:

    Bob is violating company policy, and decides to type an email to his girlfriend while he's supposed to be monitoring a manufacturing process that makes chocolate chip cookies.

    While he's typing, an alarm from the cookie dough monitoring system pops up that has an 'OK' button on it. The dialog reports: "Dang! We're out of chocolate chips! Re-fill the chocolate chip hopper and press 'OK' to resume making cookie dough."

    Well, that dialog pops in right when Bob hits the <spacebar> between two words in the email to his girlfriend. He thinks he saw something funny on the screen, but doesn't think anything of it.

    A few days later, you buy a bag of chocolate chip cookies from the Vendo while you wait for your über Qt app to compile, walk back to your desk and open it. %^*&@!#$ cookies don't have any chocolate chips in them! WTF?!

    OK, it's a little hokey, and you'd *think* that this kind of thing wouldn't happen. It has, and it does. Hell, it happened to me all the time when Lotus Notes would pop up some meeting reminder while I was coding, and I'd promise to attend some worthless random meeting and have to go clean up the mess later. Certainly, more serious Bad Things than these examples have happened, and probably are the reason for the change. It can sure be annoying, I agree, but the reasoning behind it is certainly not BS.
    Last edited by Eldritch; 6th June 2007 at 15:29. Reason: fix typo

  6. #6
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Very nice post!
    I enjoyed reading it.

    Regarding the coockies scenario -
    In KDE, I use KDESvn, and it has the annoying feature to popup a message box for each action it does.
    So if you are commiting a tree, using the keyabord is usless while the commiting is going on, and it can take some time for large projects!
    I had exactly that with an e.mail - I thought I'll write an email whie this is commiting, and I pressed a space or enter just when such a progress dialog was popped - recommit...

    So this is VERY real.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  7. #7
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Let's not deviate to speaking about unwanted popups. I just want to know how to detect if a top-level window is active or not.
    I'm having a frameless window, so the title bar does not exist and cannot show anything.
    The "'selection rectangle' around button text" sounds good, but it's too inconspicous, and besides that I only have pixmaps on my window.

    Quote Originally Posted by high_flyer View Post
    Try detecting the changed window state then with QWindowStateChangeEvent
    I'm not sure how to use it. Here is my little bogus code now. Can you help fixing it?
    Qt Code:
    1. show();
    2. raise();
    3. activateWindow();
    4. QEvent *e = new QEvent(QEvent::WindowActivate);
    5. if (!event(e))
    6. abort(); //activateWindow() failed
    7. }
    8.  
    9. bool ImageViewer::event(QEvent *e) {
    10. if (static_cast<QWindowStateChangeEvent*>(e)->oldState() == Qt::WindowActive)
    11. return true;
    12. else
    13. return false;
    14. }
    To copy to clipboard, switch view to plain text mode 

    BTW, the reasons for the policy in Windows w.r.t. window / focus 'stealing' are actually sound -- and if you dig around in MSDN you can find ways to circumvent the policy.
    Sorry, I didn't find anything.
    Last edited by ber_44; 6th June 2007 at 22:23.

  8. #8
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    I just had the idea to put activateWindow(); in a loop. Probably that would work "sooner or later" (though I still want to find a way of detecting whether the window is active or not).

  9. #9
    Join Date
    Aug 2006
    Posts
    44
    Thanked 7 Times in 7 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Have you tried QWidget::isActiveWindow() ?

    Qt's implementation in Win32 uses GetActiveWindow()... and so the return value of that function may not tell you what you really want to know.

    In Win32, GetActiveWindow() returns the 'active' window on the calling thread. That is distinctly separate from GetForegroundWindow(), which will tell you the 'active' window in the entire system. The distinction between entire system and calling thread is extremely important.

    There are corresponding "Set" functions for these in the Win32 API, and the documentation for those should lead you to more info about the activation policies -- especially SetForegroundWindow().

    Other platforms *may* have similar functions. Carbon sure does... I'm rusty in X.

  10. #10
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Quote Originally Posted by Eldritch View Post
    GetForegroundWindow(), which will tell you the 'active' window in the entire system.
    Ok, now can I do it without "Qt/MFC Migration Framework"? If yes, how?

  11. #11
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    I'm not sure how to use it. Here is my little bogus code now. Can you help fixing it?
    Try this:
    Qt Code:
    1. void ImageViewer::customEvent(QEvent *e) {
    2. if (static_cast<QWindowStateChangeEvent*>(e)->oldState() == Qt::WindowActive)
    3. {
    4. doSomething();
    5. //e->accepted(); //if apropriate
    6. return true;
    7. }
    8. else {
    9. e->ignore();
    10. return false;
    11. }
    12. }
    To copy to clipboard, switch view to plain text mode 
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  12. #12
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    As Eldritch suggested, it cannot be done with Qt.
    Would it be safe to just recompile Qt with the line
    HWND active = GetActiveWindow();
    changed in kernel\qwidget.cpp to
    HWND active = GetForegroundWindow();

  13. #13
    Join Date
    Apr 2007
    Posts
    46
    Thanks
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    I guess it wouldn't be safe, since Qt calles it internally, but I could reimplement the function with a different name just with this little change.

  14. #14
    Join Date
    Aug 2006
    Posts
    44
    Thanked 7 Times in 7 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: On "there is no reliable way to activate a window"

    Sure, you can guard your Win32 call if you need to worry about platform-specific code (e.g. #if _WIN32 or some such).

    You can check the result of GetForegroundWindow() against your QWidget::winId() value. If they are the same, your window is active, else something else is.

    You could perhaps make this even simpler, without any Win32 code.
    You can piggy-back off QWindowStateChangeEvent as high_flyer originally suggested by overriding the QWidget::changeEvent method.

    You can then check your current state (via windowState()) and make your red rectangle or whatnot to show whether your window is active.

    Qt Code:
    1. void MyWidget::changeEvent(QEvent *event)
    2. {
    3. if(event->type() == QEvent::WindowStateChanged)
    4. {
    5. if(windowState & Qt::WindowActive)
    6. setMyActiveIndicatorToGreen();
    7. else
    8. setMyActiveIndicatorToRed();
    9. }
    10. MyBaseWidgetClass::changeEvent(); // so whetever else should happen still does
    11. }
    To copy to clipboard, switch view to plain text mode 

    I didn't test it, but it *should* work if all you really want to do is *report* whether you're active, and not force yourself to be active. You could also put in a prompt, like <click here to edit> to draw the user into doing the right thing.

    Hope this helps.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.