dfct/TrueFramelessWindow

Correct Way to Handle Multiple windows?

Snow-Okami opened this issue · 2 comments

I have been trying to get multiple windows working without much luck. I don't know how to go about it at all. At first I tried pure inheritance but I couldn't get this to work without running into the diamond problem. I also don't know QT enough (specifically their QWidget class) to get this working. Then I tried a combination of inheritance and a hardcoded enum that is passed in to the constructor that tells the QWinWidget which type of class to create (widget.cpp).

When I do this however, having 2 windows open at once, causes a rendering error, as well as interaction within the windows to behave oddly. It seems as though parts of the 2 windows are controlling one another still leading the odd behavior.

I basically made copies of widget.cpp and widget.h for my different windows, and modified QWinWidget.cpp and QWinWidget.h to accept these copies and spawn different windows. These copies are derived from a basewidget.cpp (the original widget.cpp).

Is there any simple example or explanation you could provide that could aid me in this? Thanks so much.

After taking a break, and then coming back to this, I have figured out how to solve the issue. But the issue I had prior has re-emerged (the dragging windows). Here is how I solved it. Basically the static members of WinNativeWindow (childWindow and childWidget) need to become non static. By them being static it causes all windows spawn to share the same first-created window and widget. This is why the others were being controlled in strange manners as well as not occupying the full space. To do this however you must find a way to expose these to the static LRESULT CALLBACK WndProc. To do this, we transform them into pointers to save into the userdata of the window.

QWinWidget.cpp

Change:

p_ParentWinNativeWindow = new WinNativeWindow(1  * window()->devicePixelRatio()
        , 1 * window()->devicePixelRatio()
        , 1 * window()->devicePixelRatio()
        , 1 * window()->devicePixelRatio()
        , (HWND)winId()
        , this);

Delete the following:

p_ParentWinNativeWindow->childWindow = (HWND)winId();
p_ParentWinNativeWindow->childWidget = this;

WinNativeWindow.h

Change:

WinNativeWindow(const int x, const int y, const int width, const int height, const HWND hwnd, QWidget* childwidget);

HWND childWindow;
QWidget* childWidget;

WinNativeWindow.cpp

Delete (at top, above constructor):

HWND WinNativeWindow::childWindow = nullptr;
QWidget* WinNativeWindow::childWidget = nullptr;

Change (Constructor at top):

WinNativeWindow::WinNativeWindow(const int x, const int y, const int width, const int height, const HWND hwnd, QWidget* childwidget)
    : hWnd(hwnd),
      childWidget(childwidget)
{

Add (under the other SetWindowLongPtr):

SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(hWnd));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(childWidget));

Add (under LRESULT CALLBACK):

HWND* childWindow = reinterpret_cast<HWND*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
QWidget *childWidget = reinterpret_cast<QWidget*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

Change:

        case WM_CLOSE:
        {
            if (*childWindow)
            {
                SendMessage(*childWindow, WM_CLOSE, 0, 0);
                return 0;
            }
            break;
        }

After doing that, multiple windows will work, just do the same in the main.cpp as the other window to spawn a second window independent of the first:

    QWinWidget ww;

    ww.setGeometry(windowXPos, windowYPos, windowWidth, windowHeight);

    ww.show();

I'm going to continue working on this a bit and try to solve the dragging issue I am having again to get this all working.

Thank you for the solution, after some fixes, it works like a charm.

The problem is that the USERDATA can only hold one pointer.

so when you do

SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(hWnd));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(childWidget));

the USERDATA pointer is overriden by each call. a way to fix that is by grouping all the pointers we need to pass in a struct, and pass a pointer to this struct

struct userData_t
{
	WinNativeWindow* nativeWindow;
	HWND*		 childWindow;
	QWidget*	 childWidget;
};

userData_t userdata;
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(&userData));