// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \title Window Hosting Example
    \ingroup examples-widgets
    \example demos/windowhosting
    \examplecategory {User Interface Components}
    \meta {tag} {demo,gui,quick,widgets}
    \brief A demonstration of how to host non-Qt UI elements in Qt applications.

    Qt offers a wide range of UI controls for both Qt Widget and Qt Quick-based
    applications, but sometimes it may be desirable to use controls from other
    UI toolkits, such as the platform's native UI toolkit.

    To integrate these controls, we build upon the QWindow abstraction in Qt, by creating a
    QWindow representation of the native UI control, that can then be hosted within the Qt UI.
    A window created in this manner is known in Qt as a \e{foreign window}, as it represents a
    control created by a foreign (to Qt) UI toolkit.

    \section1 Creating a foreign window

    To create the QWindow representation we use QWindow::fromWinId(), passing a reference to a
    native window handle, represented by the opaque WId type.

    Each platform defines what native type the WId opaque type maps to.

    \include platformintegration.qdocinc winid-types

    The result is a QWindow that represents the native window handle.

    \include platformintegration.qdocinc winid-ownership-note

    Now, before we can create a QWindow using QWindow::fromWinId() we need a native window handle.
    In this example, we will host a month calendar control, as most platforms have it in their
    native UI toolkits, or otherwise readily available. The specifics of how to create the
    calendar on each platform are shown in the code snippets below.

    To ensure that the native handle stays alive, but is also cleaned up properly on
    application exit, we maintain a list of cleanup functions that we execute before
    returning from \c main().

    In addition to creating the native window handle and turning that into a QWindow,
    we also set a minimum size on the resulting QWindow, based on what the native toolkit
    reports as the preferred minimum size of the calendar control. This allows

    Qt to lay out the hosted foreign window properly.

    \if defined(onlinedocs)
      \tab {from-win-id}{macos}{macOS}{checked}
      \tab {from-win-id}{windows}{Windows}{}
      \tab {from-win-id}{x11}{X11}{}
      \tab {from-win-id}{ios}{iOS}{}
      \tab {from-win-id}{android}{Android}{}
      \tab {from-win-id}{webassembly}{WebAssembly}{}
    \endif

    \if defined(onlinedocs)
      \tabcontent {macos}
    \else
      \section2 macOS
    \endif
    \inlineimage macos.webp {Qt GUI, Qt Widgets, and Qt Quick windows hosting a macOS calendar}
    \snippet demos/windowhosting/main.cpp macos
    \if defined(onlinedocs)
      \endtabcontent
    \endif

    \if defined(onlinedocs)
      \tabcontent {windows}
    \else
      \section2 Windows
    \endif
    \inlineimage windows.webp
                 {Qt GUI, Qt Widgets, and Qt Quick windows hosting a Windows calendar}
    \snippet demos/windowhosting/main.cpp windows
    \if defined(onlinedocs)
      \endtabcontent
    \endif

    \if defined(onlinedocs)
      \tabcontent {x11}
    \else
      \section2 X11
    \endif
    \inlineimage x11.webp {Qt GUI, Qt Widgets, and Qt Quick windows hosting a GTK calendar}
    \snippet demos/windowhosting/main.cpp x11
    \if defined(onlinedocs)
      \endtabcontent
    \endif

    \if defined(onlinedocs)
      \tabcontent {ios}
    \else
      \section2 iOS
    \endif
    \inlineimage ios.webp {Qt GUI, Qt Widgets, and Qt Quick containers hosting an iOS calendar}

    \snippet demos/windowhosting/main.cpp ios
    \if defined(onlinedocs)
      \endtabcontent
    \endif

    \if defined(onlinedocs)
      \tabcontent {android}
    \else
      \section2 Android
    \endif
    \inlineimage android.webp {Qt GUI, Qt Widgets, and Qt Quick containers hosting an Android calendar}

    \snippet demos/windowhosting/main.cpp android
    \if defined(onlinedocs)
      \endtabcontent
    \endif

    \if defined(onlinedocs)
      \tabcontent {webassembly}
    \else
      \section2 WebAssembly
    \endif
    \inlineimage webassembly.webp {Qt GUI, Qt Widgets, and Qt Quick windows hosting a calendar on a WebAssembly calendar}
    \snippet demos/windowhosting/main.cpp webassembly
    \if defined(onlinedocs)
      \endtabcontent
    \endif

    \section1 Hosting a foreign window

    Now that we have a foreign QWindow, we can host it in a Qt UI.
    We have several options here, as described below.

    \section2 Hosting in Qt GUI

    At the lowest level, we can host the foreign window by reparenting it into
    another QWindow, via QWindow::setParent(). This approach leaves it up to
    the application developer to handle positioning, resizing, and other aspects
    of managing the hosted child window, so we generally advise against

    integrating on this level, if at all possible.

    In this example we first create a minimal container window implementation.

    \snippet demos/windowhosting/main.cpp qt-gui-container-window

    Which we can then reparent our foreign window into.

    \snippet demos/windowhosting/main.cpp qt-gui

    \section2 Hosting in Qt Widgets

    For applications built on the Qt Widgets UI stack we follow the same approach
    as for QWindow::fromWinId(), by creating a QWidget representation of the
    QWindow, via QWidget::createWindowContainer().

    We could then reparent the widget into another widget, via QWidget::setParent(),
    with the same caveats as the Qt GUI example above of having to manage positioning,
    resizing, etc. manually. In this example we prefer to add the window container
    widget to a QVBoxLayout, which allows us to automatically center the foreign
    window inside the top level widget.

    \snippet demos/windowhosting/main.cpp qt-widgets

    \section2 Hosting in Qt Quick

    Finally, for applications built on the Qt Quick UI stack, we use the WindowContainer
    item to manage the foreign window.

    \snippet demos/windowhosting/Main.qml qt-quick

    In this example the foreign window is exposed to the QML engine as an initial property,
    but this could be solved in different ways depending on the needs of the application.

    \snippet demos/windowhosting/main.cpp qt-quick
*/
