382 lines
14 KiB
C++
382 lines
14 KiB
C++
/*
|
|
This file is part of KDDockWidgets.
|
|
|
|
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
|
Author: Sérgio Martins <sergio.martins@kdab.com>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
|
|
|
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "kddockwidgets/docks_export.h"
|
|
#include "View.h"
|
|
#include "kddockwidgets/KDDockWidgets.h"
|
|
#include "kddockwidgets/QtCompat_p.h"
|
|
|
|
#include <vector>
|
|
#include <memory.h>
|
|
|
|
namespace KDDockWidgets {
|
|
|
|
namespace Core {
|
|
class DelayedCall;
|
|
class EventFilterInterface;
|
|
struct CreateViewOptions;
|
|
class ClassicDropIndicatorOverlay;
|
|
class SegmentedDropIndicatorOverlay;
|
|
class ViewFactory;
|
|
class Window;
|
|
|
|
/// @brief implements functions specific to a particular platform
|
|
/// A platform can be for example qtwidgets, qtquick, etc.
|
|
class DOCKS_EXPORT Platform
|
|
{
|
|
public:
|
|
/// @brief Enum describing the graphics stack type
|
|
enum class DisplayType {
|
|
Other = 0,
|
|
X11 = 1,
|
|
Wayland = 2,
|
|
QtOffscreen = 3,
|
|
QtEGLFS = 4,
|
|
Windows = 5
|
|
};
|
|
|
|
virtual ~Platform();
|
|
/// @brief Returns the name of the platform, only "qtwidgets" and "qtquick"
|
|
virtual const char *name() const = 0;
|
|
|
|
/// @brief Returns the platform singleton
|
|
static Platform *instance();
|
|
|
|
/// Returns whether a Platform instance exists
|
|
// Will be false at start up right before using KDDW and at shutdown after dtor runs
|
|
static bool hasInstance();
|
|
|
|
/// @brief Returns whether a popup is open
|
|
/// Usually not needed to override. Investigate further in case side bars aren't auto hiding
|
|
virtual bool hasActivePopup() const;
|
|
|
|
/// @brief Returns the focused view, if any
|
|
virtual std::shared_ptr<View> focusedView() const = 0;
|
|
|
|
/// @brief Returns all windows
|
|
virtual Vector<std::shared_ptr<Core::Window>> windows() const = 0;
|
|
|
|
/// @brief Creates and returns the default ViewFactory
|
|
virtual ViewFactory *createDefaultViewFactory() = 0;
|
|
|
|
/// @brief Returns the window at the specified global coordinates
|
|
virtual std::shared_ptr<Core::Window> windowAt(Point globalPos) const = 0;
|
|
|
|
/// @brief Sends the specified event to the specified view
|
|
virtual void sendEvent(View *, Event *) const = 0;
|
|
|
|
/// @brief Returns the screen index for the specified view or window.
|
|
/// It's up to the platform to decide how screens are ordered, kddw won't care.
|
|
virtual int screenNumberForView(View *) const = 0;
|
|
virtual int screenNumberForWindow(std::shared_ptr<Core::Window>) const = 0;
|
|
|
|
/// @brief Returns the size of the screen where this view is in
|
|
virtual Size screenSizeFor(View *) const = 0;
|
|
|
|
/// @brief Returns which screen the point is in
|
|
/// -1 if not found
|
|
virtual int screenNumberForPoint(Point) const = 0;
|
|
|
|
/// @brief Create an empty view
|
|
/// For Qt this would just returns a empty QWidget or QQuickItem
|
|
/// other frontends can return something as basic.
|
|
virtual View *createView(Controller *, View *parent = nullptr) const = 0;
|
|
|
|
/// @brief Returns whether this platform is QtWidgets
|
|
bool isQtWidgets() const;
|
|
|
|
/// @brief Returns whether this platform is QtQuick
|
|
bool isQtQuick() const;
|
|
|
|
/// @brief Returns whether this platform is Qt based
|
|
bool isQt() const;
|
|
|
|
/// @brief Returns how many pixels the mouse must move for a drag to start
|
|
/// This is usually 4 by default (QApplication::startDragDistance() for QtWidgets)
|
|
/// You can override by calling Config::setStartDragDistance(), so you don't need to create
|
|
/// a new Platform class.
|
|
int startDragDistance() const;
|
|
|
|
/// @brief Return whether we use the global event filter based mouse grabber
|
|
virtual bool usesFallbackMouseGrabber() const = 0;
|
|
|
|
/// @brief Returns whether the specified global position is on top of a view
|
|
/// that isn't draggable. This is needed since not the entire title bar is draggable.
|
|
/// For example, clicking on the close button shouldn't start a drag.
|
|
virtual bool inDisallowedDragView(Point globalPos) const = 0;
|
|
|
|
/// @brief Releases the mouse grab, if any
|
|
virtual void ungrabMouse() = 0;
|
|
|
|
/// runs the specified all after ms
|
|
/// Equivalent to QTimer::singleShot in Qt
|
|
virtual void runDelayed(int ms, Core::DelayedCall *c) = 0;
|
|
|
|
/**
|
|
* @brief Returns whether we're processing a Event::Quit
|
|
*
|
|
* Used internally to know if we should let Qt close a NonClosable dock widget at shutdown time.
|
|
*/
|
|
virtual bool isProcessingAppQuitEvent() const = 0;
|
|
|
|
/// @brief Installs a global event filter
|
|
/// Events will be forwarded to the specified EventFilterInterface
|
|
void installGlobalEventFilter(EventFilterInterface *);
|
|
|
|
/// @brief Removes a global event filter
|
|
void removeGlobalEventFilter(EventFilterInterface *);
|
|
|
|
/// @brief Returns the application name
|
|
/// This name will be used as title of floating dock widgets which contain more than 1 group
|
|
virtual QString applicationName() const = 0;
|
|
|
|
/// @brief Sets the mouse cursor to the specified shape, this has an application-wide effect
|
|
/// Call restoreMouseCursor() to set the previous cursor shape
|
|
/// @param discardLast If true, then the previous shape is discarded instead of
|
|
/// being saved into a stack for restoreMouseCursor()
|
|
virtual void setMouseCursor(Qt::CursorShape, bool discardLast = false) = 0;
|
|
|
|
/// @brief Undoes the call to setMouseCursor()
|
|
virtual void restoreMouseCursor() = 0;
|
|
|
|
/// @brief Returns the type of graphics stack being used
|
|
virtual DisplayType displayType() const = 0;
|
|
|
|
/// @brief Returns whether the left mouse button is pressed
|
|
virtual bool isLeftMouseButtonPressed() const = 0;
|
|
|
|
/// @brief Returns all available screens
|
|
virtual Vector<std::shared_ptr<Screen>> screens() const = 0;
|
|
|
|
virtual std::shared_ptr<Screen> primaryScreen() const = 0;
|
|
|
|
/// @brief For non-C++, managed languages (having a VM) prints a non-native back-trace
|
|
/// For example, the flutter frontend implements this to get a dart backtrace
|
|
/// Used for debugging only. Can be called by gdb.
|
|
virtual void dumpManagedBacktrace()
|
|
{
|
|
}
|
|
|
|
/// @brief Called when a floating window is created.
|
|
/// Overridden by flutter, so it can create a window
|
|
virtual void onFloatingWindowCreated(Core::FloatingWindow *);
|
|
|
|
/// @brief Called when a floating window is created.
|
|
/// Overridden by flutter, so it can destroy the window
|
|
virtual void onFloatingWindowDestroyed(Core::FloatingWindow *);
|
|
|
|
/// @brief Called when a main window is created.
|
|
/// Overridden by flutter, so it can create a window
|
|
/// Used by tests only. In real life users will instantiate a MainWindow in dart directly.
|
|
virtual void onMainWindowCreated(Core::MainWindow *);
|
|
|
|
/// @brief Called when a main window is created.
|
|
/// Overridden by flutter, so it can destroy the window
|
|
virtual void onMainWindowDestroyed(Core::MainWindow *);
|
|
|
|
/// Returns the mouse cursor position in screen coordinates
|
|
virtual Point cursorPos() const = 0;
|
|
|
|
/// Sets the mouse cursor position in screen coordinates
|
|
virtual void setCursorPos(Point) = 0;
|
|
|
|
/// Reads the specified and returns its content
|
|
/// The default implementation uses std::ifstream while the Qt implementation
|
|
/// uses QFile, as it needs to support QRC
|
|
virtual QByteArray readFile(const QString &, bool &ok) const;
|
|
|
|
/// Only supported on Qt, for windows
|
|
virtual bool supportsAeroSnap() const;
|
|
|
|
/// Called when the Config::viewFactory has changed
|
|
virtual void onViewFactoryChanged()
|
|
{
|
|
}
|
|
|
|
/// @brief list the list of frontend types supported by this build
|
|
static std::vector<KDDockWidgets::FrontendType> frontendTypes();
|
|
|
|
/// @brief Returns whether the Platform was already initialized
|
|
static bool isInitialized();
|
|
|
|
#if defined(DOCKS_DEVELOPER_MODE) && !defined(DARTAGNAN_BINDINGS_RUN)
|
|
/// Big timeout since lsan on github actions is very slow
|
|
#define DEFAULT_TIMEOUT 20000
|
|
|
|
// Stuff required by the tests only and not used by dart bindings.
|
|
|
|
/// @brief halts the test during the specified number of milliseconds
|
|
/// The event loop keeps running. Use this for debugging purposes so you can interact with your
|
|
/// test and see what's going on
|
|
virtual bool tests_wait(int ms) const = 0;
|
|
|
|
/// @brief Waits for the specified view to receive a resize event
|
|
/// Returns true if the view was resized until timeout was reached
|
|
virtual bool tests_waitForResize(View *, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
virtual bool tests_waitForResize(Controller *, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
virtual bool tests_waitForDeleted(View *, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
virtual bool tests_waitForDeleted(Controller *, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
|
|
/// @brief Waits for the specified window to be active (have the keyboard focus)
|
|
/// Window::isActive() should return true
|
|
/// @sa Window::isActive()
|
|
virtual bool tests_waitForWindowActive(std::shared_ptr<Core::Window>, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
|
|
/// @brief Waits for the specified view to receive the specified event
|
|
/// Returns true if the view received said event until timeout was reached
|
|
virtual bool tests_waitForEvent(Core::Object *w, Event::Type type, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
virtual bool tests_waitForEvent(View *, Event::Type type, int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
virtual bool tests_waitForEvent(std::shared_ptr<Core::Window>, Event::Type type,
|
|
int timeout = DEFAULT_TIMEOUT) const = 0;
|
|
|
|
virtual void tests_doubleClickOn(Point globalPos, View *receiver) = 0;
|
|
virtual void tests_doubleClickOn(Point globalPos, std::shared_ptr<Core::Window> receiver) = 0;
|
|
virtual void tests_pressOn(Point globalPos, View *receiver) = 0;
|
|
virtual void tests_pressOn(Point globalPos, std::shared_ptr<Core::Window> receiver) = 0;
|
|
virtual bool tests_releaseOn(Point globalPos, View *receiver) = 0;
|
|
virtual bool tests_mouseMove(Point globalPos, View *receiver) = 0;
|
|
|
|
/// @brief Creates a Window. For the sole purpose of unit-testing Window.
|
|
/// The created window should be visible.
|
|
virtual std::shared_ptr<Core::Window> tests_createWindow() = 0;
|
|
|
|
/// @brief Creates the platform. Called by the tests at startup.
|
|
/// For any custom behaviour in your derived Platform override tests_initPlatform_impl()
|
|
static void tests_initPlatform(int &argc, char *argv[], KDDockWidgets::FrontendType, bool defaultToOffscreenQPA = true);
|
|
|
|
/// @brief Deletes the platform. Called at end of tests.
|
|
/// For any custom behaviour in your derived Platform override tests_deinitPlatform_impl()
|
|
static void tests_deinitPlatform();
|
|
|
|
std::string m_expectedWarning;
|
|
#endif
|
|
|
|
#ifdef DOCKS_TESTING_METHODS
|
|
|
|
class WarningObserver
|
|
{
|
|
KDDW_DELETE_COPY_CTOR(WarningObserver)
|
|
public:
|
|
WarningObserver() = default;
|
|
virtual ~WarningObserver();
|
|
virtual void onFatal() = 0;
|
|
};
|
|
|
|
/// @brief Creates a view with the specified parent
|
|
/// If the parent is null then a new window is created and the returned view will be the root
|
|
/// view
|
|
virtual View *tests_createView(CreateViewOptions, View *parent = nullptr) = 0;
|
|
|
|
/// @brief Returns a view that can have keyboard focus
|
|
/// For example a line edit. This is used to for testing focus related features.
|
|
virtual View *tests_createFocusableView(CreateViewOptions, View *parent = nullptr) = 0;
|
|
|
|
/// @brief Returns a view that rejects close events
|
|
virtual View *tests_createNonClosableView(View *parent = nullptr) = 0;
|
|
|
|
virtual void installMessageHandler() = 0;
|
|
virtual void uninstallMessageHandler() = 0;
|
|
|
|
/// @brief Creates a main window. This is not API that the user will use, but used
|
|
/// internally by some tools that need a main window
|
|
virtual Core::MainWindow *
|
|
createMainWindow(const QString &uniqueName, CreateViewOptions,
|
|
MainWindowOptions options = MainWindowOption_HasCentralGroup,
|
|
View *parent = nullptr, Qt::WindowFlags = {}) const = 0;
|
|
|
|
virtual void pauseForDebugger();
|
|
|
|
protected:
|
|
/// @brief Implement any needed initializations before tests starting to run, if any
|
|
/// Override in derived classes for custom behavior.
|
|
virtual void tests_initPlatform_impl()
|
|
{
|
|
}
|
|
|
|
/// @brief Implement any needed cleanup after the tests runs, if any
|
|
/// Override in derived classes for custom behavior.
|
|
virtual void tests_deinitPlatform_impl()
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
public:
|
|
class Private;
|
|
Private *const d;
|
|
|
|
protected:
|
|
virtual int startDragDistance_impl() const;
|
|
Platform();
|
|
|
|
Platform(const Platform &) = delete;
|
|
Platform &operator=(const Platform &) = delete;
|
|
};
|
|
|
|
#if defined(DOCKS_DEVELOPER_MODE)
|
|
|
|
#if !defined(DARTAGNAN_BINDINGS_RUN)
|
|
|
|
struct SetExpectedWarning
|
|
{
|
|
explicit SetExpectedWarning(const std::string &s)
|
|
{
|
|
if (!s.empty())
|
|
Platform::instance()->m_expectedWarning = s;
|
|
}
|
|
|
|
~SetExpectedWarning()
|
|
{
|
|
Platform::instance()->m_expectedWarning.clear();
|
|
}
|
|
|
|
KDDW_DELETE_COPY_CTOR(SetExpectedWarning)
|
|
};
|
|
|
|
#endif // bindings
|
|
|
|
#endif // dev-mode
|
|
|
|
#if defined(DOCKS_TESTING_METHODS)
|
|
|
|
struct CreateViewOptions
|
|
{
|
|
bool isVisible = false;
|
|
Size sizeHint = {};
|
|
Size minSize = { 0, 0 };
|
|
Size maxSize = Size(16777215, 16777215);
|
|
Size size = { 1000, 1000 };
|
|
bool createWindow = false;
|
|
|
|
Size getMinSize() const
|
|
{
|
|
return minSize;
|
|
}
|
|
|
|
Size getMaxSize() const
|
|
{
|
|
return maxSize;
|
|
}
|
|
|
|
Size getSize() const
|
|
{
|
|
return size;
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
} // Core
|
|
|
|
} // KDDockWidgets
|