Window manager. Interne inhoud van X-vensters in een afzonderlijk venster?

Ik schrijf mijn eigen Window Manager met Xlib en Qt 4.7. Dus in mijn applicatie vang ik alle evenementen van XServer.

Het probleem is de volgende. Wanneer ik het venster "MapRequest" laat zien, wordt de interne inhoud soms weergegeven in een afzonderlijk venster. Meestal sta ik met dit probleem in browsers (zoals Firefox en Google Chrome) na het openen van een nieuwe webpagina, soms in Qt Creator en Dolphin na een open dialoogvenster, ook in mediaspelers. Wat kan daar een reden voor zijn? Wat heb ik gemist?

Alle adviezen zijn welkom.

Hier is MapRequest-handler.

bool Manager::mapRequestHandler(XEvent* pEvent)
{
    Window lWindow = pEvent->xmaprequest.window;

    QMWindowWidget* lWidget = findWidget(lWindow);
    if (!lWidget)
    {
        lWidget = (QMWindowWidget*)QWidget::find(lWindow);
    }

    if (lWidget)
    {
        XMapWindow(QX11Info::display(), lWindow);
        lWidget->show();
        XRaiseWindow(QX11Info::display(), lWidget->winId());
        return true;
    }
    else
    {
        qDebug()<<"CREATING WINDOW IN MAP_REQUEST...";
        createClientWindow(lWindow); //this function calls only here.
        qDebug()<<"WINDOW CREATED";
        return true;
    }
    return false;
}

Hier is de functie createClientWindow ().

void Manager::createClientWindow(Qt::HANDLE pWinID)
{
    XWindowAttributes lWinAttr;
    if(!XGetWindowAttributes(QX11Info::display(), pWinID, &lWinAttr))
    {
        return;
    }
    if(lWinAttr.override_redirect)
    {
        return;
    }

    QStringList lWindowType = getWindowType(pWinID);
    if(lWindowType[0] == "Desktop")
    {
        return;
    }
    else if(lWindowType[0] == "Splash"       || lWindowType[0] == "Dock" ||
            lWindowType[0] == "KDE_override" || lWindowType[0] == "Popup_menu")
    {
        XMapWindow(QX11Info::display(), pWinID);
        XRaiseWindow(QX11Info::display(), pWinID);
        return;
    }
    else
    {
        QMWindowWidget *lWindowWidget = new QMWindowWidget(pWinID, lWinAttr);
        connect(lWindowWidget, SIGNAL(destroyed(QObject*)), this, SLOT(slotWidgetDestroyed(QObject*)));
        mListWindows.append(lWindowWidget);
    }
}

Constructor van QMWindowWidget.

mClientAttr = pWinAttr;
mWmHints = XGetWMHints(QX11Info::display(), pWindow);

XGrabServer(QX11Info::display());

XTextProperty lTitle;
XGetWMName(QX11Info::display(), pWindow, &lTitle);
this->setWindowTitle(QString::fromUtf8((const char*)lTitle.value));
qDebug()<<(const char*)lTitle.value;

int widgetX = pWinAttr.x - 3;
int widgetY = pWinAttr.y - 33;
if (widgetX < 0)
{
    widgetX = 0;
}
if (widgetY < 0)
{
    widgetY = 0;
}
XAddToSaveSet(QX11Info::display(), pWindow);
XSetWindowBorderWidth(QX11Info::display(), pWindow, 0);
XResizeWindow(QX11Info::display(), pWindow, pWinAttr.width, pWinAttr.height);
this->setGeometry(widgetX, widgetY, pWinAttr.width + 6, pWinAttr.height + 33);

XSelectInput(QX11Info::display(),this->winId(),
             KeyReleaseMask | KeyPressMask |
             ButtonMotionMask|
             ButtonPressMask | ButtonReleaseMask |
             FocusChangeMask |
             ExposureMask |
             StructureNotifyMask |
             SubstructureNotifyMask |
             SubstructureRedirectMask);

XReparentWindow(QX11Info::display(), pWindow, this->winId(), 3, 30);

XSelectInput(QX11Info::display(), pWindow,
             ColormapChangeMask |
             PropertyChangeMask |
             StructureNotifyMask);

this->show();
XMapWindow(QX11Info::display(), pWindow);
XRaiseWindow(QX11Info::display(), this->winId());
XSetInputFocus(QX11Info::display(), pWindow, RevertToParent, CurrentTime);

XUngrabServer(QX11Info::display());
XSync(QX11Info::display(), false);
0

1 antwoord

Het probleem is dat je ALLEEN je vensters op het hoogste niveau moet tonen, en alleen wanneer ze geacht worden te worden getoond. Ik had hetzelfde probleem en ik ontdekte dat ik het clientvenster op meer plaatsen dan MapRequest-gebeurtenishandler liet zien! Dus controleer je code, misschien ben je bezig met een andere gebeurtenis die een venster toont zonder expliciet verzoek!

Als je verdere hulp nodig hebt, plaats dan al je event handlers, becommentarieer mijn antwoord, ik zal het bewerken en probeer je hulp te bieden.

0
toegevoegd
Voeg uw code alstublieft niet toe als afzonderlijke antwoorden, maar bewerk uw vraag in plaats daarvan.
toegevoegd de auteur AlQafir, de bron
Wanneer u vervolgens een flitsobject op een webpagina ziet, is dit een X-venster. Wanneer u op de knop op het volledige scherm klikt, moet het venster worden hersteld als een venster op het hoogste niveau en van grootte worden gewijzigd. Bent u het vergeten om de override_redirect-vlag in uw ReparentNotify-handler te gebruiken?
toegevoegd de auteur AlQafir, de bron
Ik heb de oorzaak van het probleem al gevonden. Ik had één vreemde vlag in gebeurtenismasker voor cliënten (SubstructureRedirectMask). Deze vlag is alleen nodig voor het rootvenster en mijn eigen vensters die ik maak. Maar in één geval werkt het nog steeds niet. Wanneer ik een video op een webpagina heb (bijvoorbeeld op YouTube) en probeer deze uit te breiden naar volledig scherm, wordt de video in een afzonderlijk venster weergegeven. Ik weet zeker dat ik geen grenzen maak op andere plaatsen behalve MapRequest. Misschien is mijn controle voor "top-level window" niet correct?
toegevoegd de auteur Nemo, de bron
Ik heb helemaal geen ReparentNotify-handler. Maar ik heb debug output van deze gebeurtenis en ik ontvang ReparentNotify niet van venster met video, alleen MapRequest. En debug-uitvoer in MapRequest zegt dat het "top-level" niet "override_redirect" -venster is. En het heeft NORMAAL type. Ik vraag me af hoe ik weet dat dit venster geen randen moet hebben. Wat hebben eigenschappen anders kunnen beïnvloeden?
toegevoegd de auteur Nemo, de bron