Вікно менеджера. Внутрішній вміст X-вікон у окремому вікні?

Я пишу власний менеджер вікон за допомогою Xlib та Qt 4.7. Так що в моєму застосуванні я спіймаю всі події з XServer.

Проблема наступна. Коли я показую вікно на події "MapRequest", іноді його внутрішній вміст відображається в окремому вікні. Найчастіше я стикаюсь з цією проблемою в браузерах (наприклад, Firefox і Google Chrome) після відкриття нової веб-сторінки, іноді в Qt Creator і Dolphin після відкритого діалогового вікна, також у медіа-програвачі. Що може бути причиною цього? Що я пропустив?

Будь-які поради вітаються.

Ось обробник MapRequest.

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;
}

Ось функція 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);
    }
}

Конструктор 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 Відповіді

Проблема полягає в тому, що ви повинні показувати ТІЛЬКИ лише вікна верхнього рівня, і лише тоді, коли вони повинні бути показані. У мене те ж саме питання, і я виявив, що показую клієнтське вікно в більшості місць, а потім обробника події MapRequest! Тому перевірте свій код, можливо, ви обробляєте іншу подію, яка показує вікно без явного запиту!

Якщо вам потрібна додаткова допомога, будь-ласка, опублікуйте всі ваші обробники подій, тоді коментуйте мою відповідь, я її відредагую і спробую допомогти вам.

0
додано
Будь ласка, не додавайте свій код як окремі відповіді, а потім змініть своє запитання.
додано Автор AlQafir, джерело
Тоді, коли ви побачите флеш-об'єкт на веб-сторінці, це вікно X. Коли ви натискаєте повноекранну кнопку, вікно має бути виправлено як вікно верхнього рівня та змінено розмір. Ви забули використати прапорець override_redirect у своєму обробнику ReparentNotify?
додано Автор AlQafir, джерело
Я вже знайшов причину випуску. У мене був один непарний прапор у масках подій для клієнтів (SubstructureRedirectMask). Цей прапорець потрібен тільки для кореневого вікна та моїх власних вікон, які я створюю. Але в одному випадку він все одно не працює. Коли у мене є відео на веб-сторінці (наприклад, на YouTube) і спробуйте розгорнути його в повноекранному режимі, відео з'являється в окремому вікні. Я впевнений, що я не створюю кордонів в інших місцях за винятком MapRequest. Може, моя перевірка на "вікно верхнього рівня" неправильна?
додано Автор Nemo, джерело
Я взагалі не має обробника ReparentNotify. Але я налагоджував вихід цієї події, і я не отримую ReparentNotify з вікна з відео, тільки MapRequest. І виправлення помилок в MapRequest говорить, що це вікно "верхнього рівня", а не "override_redirect". І це має тип NORMAL. Цікаво знати, що це вікно не повинно мати кордонів. Які ще властивості можуть вплинути на це?
додано Автор Nemo, джерело