Click here to Skip to main content
16,004,458 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I am using Qt for Windows.
I would like to have a window with a system menu and a dynamic Frameless flag. Without the Frameless flag, the window should have a system menu with a few additional entries; the user is free to toggle the Frameless flag on demand (e.g. by clicking a button), and the window should adjust.

I found a solution for the Windows system menu, using the Win32 API and a native event filter. The problem is that, when I install a native event filter, setting the Framless flag crashes the application (stack overflow).

I made a minimal example. Am I doing something wrong? Thank you for any hint.

Here is the code:

gui.h
C++
#ifndef GUI_H
#define GUI_H

#include <QWidget>

namespace Ui {
class gui;
}

class gui : public QWidget
{
    Q_OBJECT

public:
    explicit gui(QWidget *parent = 0);
    ~gui();

private:
    //Ui::gui *ui;
};

#endif // GUI_H


gui.cpp
C++
#include "gui.h"
//#include "ui_gui.h"

#include <qt_windows.h>
#include <QAbstractNativeEventFilter>
#include <QDebug>
#include <QMessageBox>
#include <QAbstractEventDispatcher>


#define MENUITEM_ABOUT 4324
gui *wnd = NULL;   // For the global EventFilter

class GlobalEventFilter : public QAbstractNativeEventFilter
{
    virtual bool nativeEventFilter(const QByteArray & /*eventType*/, void * message, long * /*result*/)
    {
        MSG *msg = (MSG*)message;

        if (wnd && msg->hwnd == (HWND) wnd->winId())
        {
            if(msg->message == WM_SYSCOMMAND)
            {
                if(msg->wParam == MENUITEM_ABOUT)
                {
                    qDebug() << "ABOUT";
                    //wnd->emitSignalAbout();
                    return true;
                }
            }
        }

        return false;
    }
} globalEventFilter;


gui::gui(QWidget *parent) :
    QWidget(parent)
//    ,ui(new Ui::gui)
{
    wnd = this;

    HMENU hMenu = ::GetSystemMenu((HWND) winId(), false);
    ::AppendMenu(hMenu, MF_SEPARATOR, 1, L"Separator");
    ::AppendMenu(hMenu, MF_STRING, MENUITEM_ABOUT, L"About");
    QAbstractEventDispatcher::instance(0)->installNativeEventFilter(&globalEventFilter);

    QAbstractEventDispatcher::instance(0)->removeNativeEventFilter(&globalEventFilter);
    setWindowFlag(Qt::FramelessWindowHint, true);
    QAbstractEventDispatcher::instance(0)->installNativeEventFilter(&globalEventFilter);

    //ui->setupUi(this);
}

gui::~gui()
{
    //delete ui;
}


What I have tried:

If I remove either the setWindowFlag, or the installNativeEventFilter calls, all works fine. With both of them, I get the stack overflow crash. If I move the setWindowFlag at the beginning of the function, it does not crash for some reason; if I toggle the flag later though, it crashes.
Posted

1 solution

I encountered the same problem recently, and seems like the infinite recursion is caused by calling QWindow::winId() or QWidget::winId() inside QAbstractNativeEventFilter::nativeEventFilter.

I moved the `winId()` call to the constructor of QAbstractNativeEventFilter and the problem is solved:
C++
#include <QAbstractNativeEventFilter>

class NativeEventFilter: public QAbstractNativeEventFilter
{
public:
    NativeEventFilter(QWindow& window):
        wid_(window.winId()) {}
    bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr* result)
    {
        HWND hwnd = (HWND)wid_;
        // Use hwnd
    }
private:
    WId wid_;
};


I used it on QWindow, and it works fine. But QWidget might have its winId changed, so you might have to handle the corresponding event (see QEvent::Type::WinIdChange).
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900