Changeset 432


Ignore:
Timestamp:
Dec 18, 2009, 2:36:30 AM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: Fixed: Popups shown when another application is active were not controllable with keyboard and didn't close on an outside mouse click (closes #113).

Location:
trunk/src/gui
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/src/gui/kernel/qapplication_pm.cpp

    r428 r432  
    110110QPointer<QWidget> qt_last_mouse_receiver = 0;
    111111
     112static HWND foreignActiveWnd = NULLHANDLE;
     113static HWND foreignFocusWnd = NULLHANDLE;
     114
    112115static HWND autoCaptureWnd = NULLHANDLE;
    113116static bool autoCaptureReleased = FALSE;
     
    10161019            }
    10171020
    1018             case WM_SETFOCUS: {
     1021            case WM_FOCUSCHANGE: {
    10191022                HWND hwnd = (HWND)mp1;
    10201023                bool focus = SHORT1FROMMP(mp2);
     
    10231026                        // we don't get focus, so unset it now
    10241027                        if (QApplication::activePopupWidget()) {
     1028                            foreignFocusWnd = hwnd;
    10251029                            // Another application was activated while our popups are open,
    10261030                            // then close all popups.  In case some popup refuses to close,
     
    14371441        return;
    14381442
    1439     if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) {
    1440         Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
    1441         setAutoCapture(popup->d_func()->frameWinId()); // grab mouse/keyboard
    1442     }
     1443    if (QApplicationPrivate::popupWidgets->count() == 1) {
     1444        if (!qt_nograb()) {
     1445            Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
     1446            setAutoCapture(popup->d_func()->frameWinId()); // grab mouse/keyboard
     1447        }
     1448        if (!qWidgetFromHWND(WinQueryActiveWindow(HWND_DESKTOP))) {
     1449            // the popup is opened while another application is active. Steal
     1450            // the focus (to receive keyboard input and to make sure we get
     1451            // WM_FOCUSCHANGE when clicked outside) but not the active state.
     1452            ULONG flags = FC_NOSETACTIVE | FC_NOLOSEACTIVE;
     1453            WinFocusChange(HWND_DESKTOP, popup->d_func()->frameWinId(), flags);
     1454            foreignActiveWnd = WinQueryActiveWindow(HWND_DESKTOP);
     1455        }
     1456    }
     1457
    14431458    // Popups are not focus-handled by the window system (the first
    14441459    // popup grabbed the keyboard), so we have to do that manually: A
     
    14641479    curPos.y = q_func()->desktop()->height() - (curPos.y + 1);
    14651480
    1466     if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
     1481    if (QApplicationPrivate::popupWidgets->isEmpty()) {
     1482        // this was the last popup
     1483        if (foreignActiveWnd != NULLHANDLE && foreignFocusWnd != NULLHANDLE) {
     1484            // we stole focus from another application so PM won't send it
     1485            // WM_ACTIVATE(FALSE). Our duty is to do it for PM.
     1486            HWND parent, desktop = WinQueryDesktopWindow(0, NULLHANDLE);
     1487            // find the top-level window of the window actually getting focus
     1488            while ((parent = WinQueryWindow(foreignFocusWnd, QW_PARENT)) != desktop)
     1489                foreignFocusWnd = parent;
     1490            // send deactivation to the old active window if it differs
     1491            if (foreignFocusWnd != foreignActiveWnd)
     1492                WinSendMsg(foreignActiveWnd, WM_ACTIVATE, (MPARAM)FALSE, (MPARAM)foreignActiveWnd);
     1493        }
     1494        foreignActiveWnd = NULLHANDLE;
     1495        foreignFocusWnd = NULLHANDLE;
     1496
    14671497        delete QApplicationPrivate::popupWidgets;
    14681498        QApplicationPrivate::popupWidgets = 0;
     
    25532583        HWND hwnd = (HWND)qmsg.mp2;
    25542584        str += QCStr(" Active(") + QCStr(active ? "TRUE) " : "FALSE)");
    2555         str += QString().sprintf(" hwnd %08lX.", hwnd);
     2585        str += QString().sprintf(" hwndActive %08lX.", hwnd);
    25562586        str += qWidgetName(qWidgetFromHWND(hwnd));
    25572587        break;
     
    25622592        bool focus = SHORT1FROMMP(qmsg.mp2);
    25632593        str += QCStr(" Focus(") + QCStr(focus ? "TRUE) " : "FALSE)");
    2564         str += QString().sprintf(" hwnd %08lX.", hwnd);
     2594        str += QString().sprintf(" hwndFocus %08lX.", hwnd);
    25652595        str += qWidgetName(qWidgetFromHWND(hwnd));
     2596        break;
     2597    myCaseEnd()
     2598
     2599    myCaseBegin(WM_FOCUSCHANGE)
     2600        HWND hwnd = (HWND)qmsg.mp1;
     2601        bool focus = SHORT1FROMMP(qmsg.mp2);
     2602        bool fl = SHORT2FROMMP(qmsg.mp2);
     2603        QString flstr;
     2604        myDefFlagEx(fl, FC_NOSETFOCUS, flstr, "NOSETFCS");
     2605        myDefFlagEx(fl, FC_NOLOSEFOCUS, flstr, "NOLOSEFCS");
     2606        myDefFlagEx(fl, FC_NOSETACTIVE, flstr, "NOSETACT");
     2607        myDefFlagEx(fl, FC_NOLOSEACTIVE, flstr, "NOLOSEACT");
     2608        myDefFlagEx(fl, FC_NOSETSELECTION, flstr, "NOSETSEL");
     2609        myDefFlagEx(fl, FC_NOLOSESELECTION, flstr, "NOSETSEL");
     2610        str += QCStr(" Focus(") + QCStr(focus ? "TRUE) " : "FALSE)");
     2611        str += QString().sprintf(" hwndFocus %08lX.", hwnd);
     2612        str += qWidgetName(qWidgetFromHWND(hwnd));
     2613        str += QCStr(" FC(") + flstr + QCStr(")");
    25662614        break;
    25672615    myCaseEnd()
  • TabularUnified trunk/src/gui/util/qsystemtrayicon_pm.cpp

    r286 r432  
    158158}
    159159
     160static void closeNormalPopups()
     161{
     162    if (QApplication::activePopupWidget()) {
     163        // The system tray area is actually another application so we close all
     164        // normal popups for consistency (see qapplication_pm.cpp). In case some
     165        // popup refuses to close, we give up after 1024 attempts (to avoid an
     166        // infinite loop).
     167        int maxiter = 1024;
     168        QWidget *popup;
     169        while ((popup = QApplication::activePopupWidget()) && maxiter--)
     170            popup->close();
     171    }
     172}
     173
    160174bool QSystemTrayIconSys::pmEvent(QMSG *msg, MRESULT *result)
    161175{
     
    165179            switch (SHORT2FROMMP(msg->mp1)) {
    166180                case XST_IN_MOUSE: {
     181                    closeNormalPopups();
    167182                    PXSTMOUSEMSG pMsg = (PXSTMOUSEMSG)msg->mp2;
    168183                    switch (pMsg->ulMouseMsg) {
     
    182197                }
    183198                case XST_IN_CONTEXT: {
     199                    closeNormalPopups();
     200                    if (QApplication::activePopupWidget()) {
     201                        // The system tray area is actually another application
     202                        // so we close all normal popups for consistency (see
     203                        // qapplication_pm.cpp). In case some popup refuses to
     204                        // close, we give up after 1024 attempts (to avoid an
     205                        // infinite loop).
     206                        int maxiter = 1024;
     207                        QWidget *popup;
     208                        while ((popup=QApplication::activePopupWidget()) && maxiter--)
     209                            popup->close();
     210                    }
    184211                    PXSTCONTEXTMSG pMsg = (PXSTCONTEXTMSG)msg->mp2;
    185212                    if (q->contextMenu()) {
     
    196223                    break;
    197224                }
     225                case XST_IN_WHEEL: {
     226                    closeNormalPopups();
     227                }
    198228                default:
    199229                    break;
Note: See TracChangeset for help on using the changeset viewer.