DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

Window.hpp (18488B)


      1 /*
      2  * DISTRHO Plugin Framework (DPF)
      3  * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
      6  * or without fee is hereby granted, provided that the above copyright notice and this
      7  * permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
     10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
     11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #ifndef DGL_WINDOW_HPP_INCLUDED
     18 #define DGL_WINDOW_HPP_INCLUDED
     19 
     20 #include "Geometry.hpp"
     21 
     22 #ifndef DGL_FILE_BROWSER_DISABLED
     23 # include "FileBrowserDialog.hpp"
     24 #endif
     25 
     26 #include <vector>
     27 
     28 #ifdef DISTRHO_NAMESPACE
     29 START_NAMESPACE_DISTRHO
     30 class PluginWindow;
     31 END_NAMESPACE_DISTRHO
     32 #endif
     33 
     34 START_NAMESPACE_DGL
     35 
     36 class Application;
     37 class TopLevelWidget;
     38 
     39 // -----------------------------------------------------------------------
     40 
     41 /**
     42    DGL Window class.
     43 
     44    This is the where all OS-related events initially happen, before being propagated to any widgets.
     45 
     46    A Window MUST have an Application instance tied to it.
     47    It is not possible to swap Application instances from within the lifetime of a Window.
     48    But it is possible to completely change the Widgets that a Window contains during its lifetime.
     49 
     50    Typically the event handling functions as following:
     51    Application -> Window -> Top-Level-Widget -> SubWidgets
     52 
     53    Please note that, unlike many other graphical toolkits out there,
     54    DGL makes a clear distinction between a Window and a Widget.
     55    You cannot directly draw in a Window, you need to create a Widget for that.
     56 
     57    Also, a Window MUST have a single top-level Widget.
     58    The Window will take care of global screen positioning and resizing, everything else is sent for widgets to handle.
     59 
     60    ...
     61  */
     62 class DISTRHO_API Window
     63 {
     64    struct PrivateData;
     65 
     66 public:
     67    /**
     68       Window graphics context as a scoped struct.
     69       This class gives graphics context drawing time to a window's widgets.
     70       Typically used for allowing OpenGL drawing operations during a window + widget constructor.
     71 
     72       Unless you are subclassing the Window or StandaloneWindow classes, you do not need to care.
     73       In such cases you will need to use this struct as a way to get a valid OpenGL context.
     74       For example in a standalone application:
     75       ```
     76       int main()
     77       {
     78           Application app;
     79           Window win(app);
     80           ScopedPointer<MyCustomTopLevelWidget> widget;
     81           {
     82               const Window::ScopedGraphicsContext sgc(win);
     83               widget = new MyCustomTopLevelWidget(win);
     84           }
     85           app.exec();
     86           return 0;
     87       }
     88       ```
     89 
     90       This struct is necessary because we cannot automatically make the window leave the OpenGL context in custom code.
     91       And we must always cleanly enter and leave the OpenGL context.
     92       So in order to avoid messing up the global host context, this class is used around widget creation.
     93     */
     94     struct ScopedGraphicsContext
     95     {
     96         /** Constructor that will make the @a window graphics context the current one */
     97         explicit ScopedGraphicsContext(Window& window);
     98 
     99         /** Overloaded constructor, gives back context to its transient parent when done */
    100         explicit ScopedGraphicsContext(Window& window, Window& transientParentWindow);
    101 
    102         /** Desstructor for clearing current context, if not done yet */
    103         ~ScopedGraphicsContext();
    104 
    105         /** Early context clearing, useful for standalone windows not created by you. */
    106         void done();
    107 
    108         /** Get a valid context back again. */
    109         void reinit();
    110 
    111         DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext)
    112         DISTRHO_PREVENT_HEAP_ALLOCATION
    113 
    114     private:
    115         Window& window;
    116         Window::PrivateData* const ppData;
    117         bool active;
    118         bool reenter;
    119     };
    120 
    121    /**
    122       Constructor for a regular, standalone window.
    123     */
    124     explicit Window(Application& app);
    125 
    126    /**
    127       Constructor for a modal window, by having another window as its transient parent.
    128       The Application instance must be the same between the 2 windows.
    129     */
    130     explicit Window(Application& app, Window& transientParentWindow);
    131 
    132    /**
    133       Constructor for an embed Window without known size,
    134       typically used in modules or plugins that run inside another host.
    135     */
    136     explicit Window(Application& app,
    137                     uintptr_t parentWindowHandle,
    138                     double scaleFactor,
    139                     bool resizable);
    140 
    141    /**
    142       Constructor for an embed Window with known size,
    143       typically used in modules or plugins that run inside another host.
    144     */
    145     explicit Window(Application& app,
    146                     uintptr_t parentWindowHandle,
    147                     uint width,
    148                     uint height,
    149                     double scaleFactor,
    150                     bool resizable);
    151 
    152    /**
    153       Destructor.
    154     */
    155     virtual ~Window();
    156 
    157    /**
    158       Whether this Window is embed into another (usually not DGL-controlled) Window.
    159     */
    160     bool isEmbed() const noexcept;
    161 
    162    /**
    163       Check if this window is visible / mapped.
    164       Invisible windows do not receive events except resize.
    165       @see setVisible(bool)
    166     */
    167     bool isVisible() const noexcept;
    168 
    169    /**
    170       Set window visible (or not) according to @a visible.
    171       Only valid for standalones, embed windows are always visible.
    172       @see isVisible(), hide(), show()
    173     */
    174     void setVisible(bool visible);
    175 
    176    /**
    177       Show window.
    178       This is the same as calling setVisible(true).
    179       @see isVisible(), setVisible(bool)
    180     */
    181     void show();
    182 
    183    /**
    184       Hide window.
    185       This is the same as calling setVisible(false).
    186       @see isVisible(), setVisible(bool)
    187     */
    188     void hide();
    189 
    190    /**
    191       Hide window and notify application of a window close event.
    192       The application event-loop will stop when all windows have been closed.
    193       For standalone windows only, has no effect if window is embed.
    194       @see isEmbed()
    195 
    196       @note It is possible to hide the window while not stopping the event-loop.
    197             A closed window is always hidden, but the reverse is not always true.
    198     */
    199     void close();
    200 
    201    /**
    202       Check if this window is resizable (by the user or window manager).
    203       @see setResizable
    204     */
    205     bool isResizable() const noexcept;
    206 
    207    /**
    208       Set window as resizable (by the user or window manager).
    209       It is always possible to resize a window programmatically, which is not the same as the user being allowed to it.
    210       @note This function does nothing for plugins, where the resizable state is set via macro.
    211       @see DISTRHO_UI_USER_RESIZABLE
    212     */
    213     void setResizable(bool resizable);
    214 
    215    /**
    216       Get X offset, typically 0.
    217     */
    218     int getOffsetX() const noexcept;
    219 
    220    /**
    221       Get Y offset, typically 0.
    222     */
    223     int getOffsetY() const noexcept;
    224 
    225    /**
    226       Get offset.
    227     */
    228     Point<int> getOffset() const noexcept;
    229 
    230    /**
    231       Set X offset.
    232     */
    233     void setOffsetX(int x);
    234 
    235    /**
    236       Set Y offset.
    237     */
    238     void setOffsetY(int y);
    239 
    240    /**
    241       Set offset using @a x and @a y values.
    242     */
    243     void setOffset(int x, int y);
    244 
    245    /**
    246       Set offset.
    247     */
    248     void setOffset(const Point<int>& offset);
    249 
    250    /**
    251       Get width.
    252     */
    253     uint getWidth() const noexcept;
    254 
    255    /**
    256       Get height.
    257     */
    258     uint getHeight() const noexcept;
    259 
    260    /**
    261       Get size.
    262     */
    263     Size<uint> getSize() const noexcept;
    264 
    265    /**
    266       Set width.
    267     */
    268     void setWidth(uint width);
    269 
    270    /**
    271       Set height.
    272     */
    273     void setHeight(uint height);
    274 
    275    /**
    276       Set size using @a width and @a height values.
    277     */
    278     void setSize(uint width, uint height);
    279 
    280    /**
    281       Set size.
    282     */
    283     void setSize(const Size<uint>& size);
    284 
    285    /**
    286       Get the title of the window previously set with setTitle().
    287     */
    288     const char* getTitle() const noexcept;
    289 
    290    /**
    291       Set the title of the window, typically displayed in the title bar or in window switchers.
    292 
    293       This only makes sense for non-embedded windows.
    294     */
    295     void setTitle(const char* title);
    296 
    297    /**
    298       Check if key repeat events are ignored.
    299     */
    300     bool isIgnoringKeyRepeat() const noexcept;
    301 
    302    /**
    303       Set to ignore (or not) key repeat events according to @a ignore.
    304     */
    305     void setIgnoringKeyRepeat(bool ignore) noexcept;
    306 
    307    /**
    308       Get the clipboard contents.
    309 
    310       This gets the system clipboard contents,
    311       which may have been set with setClipboard() or copied from another application.
    312 
    313       Returns the clipboard contents, or null.
    314 
    315       @note By default only "text/plain" mimetype is supported and returned.
    316             Override onClipboardDataOffer for supporting other types.
    317     */
    318     const void* getClipboard(size_t& dataSize);
    319 
    320    /**
    321       Set the clipboard contents.
    322 
    323       This sets the system clipboard contents,
    324       which can be retrieved with getClipboard() or pasted into other applications.
    325 
    326       If using a string, the use of a null terminator is required (and must be part of dataSize).@n
    327       The MIME type of the data "text/plain" is assumed if null is used.
    328     */
    329     bool setClipboard(const char* mimeType, const void* data, size_t dataSize);
    330 
    331    /**
    332       Set the mouse cursor.
    333 
    334       This changes the system cursor that is displayed when the pointer is inside the window.
    335       May fail if setting the cursor is not supported on this system,
    336       for example if compiled on X11 without Xcursor support.
    337     */
    338     bool setCursor(MouseCursor cursor);
    339 
    340    /**
    341       Add a callback function to be triggered on every idle cycle or on a specific timer frequency.
    342       You can add more than one, and remove them at anytime with removeIdleCallback().
    343       This can be used to perform some action at a regular interval with relatively low frequency.
    344 
    345       If providing a timer frequency, there are a few things to note:
    346        1. There is a platform-specific limit to the number of supported timers, and overhead associated with each,
    347           so you should create only a few timers and perform several tasks in one if necessary.
    348        2. This timer frequency is not guaranteed to have a resolution better than 10ms
    349           (the maximum timer resolution on Windows) and may be rounded up if it is too short.
    350           On X11 and MacOS, a resolution of about 1ms can usually be relied on.
    351     */
    352     bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0);
    353 
    354    /**
    355       Remove an idle callback previously added via addIdleCallback().
    356     */
    357     bool removeIdleCallback(IdleCallback* callback);
    358 
    359    /**
    360       Get the application associated with this window.
    361     */
    362     Application& getApp() const noexcept;
    363 
    364    /**
    365       Get the graphics context associated with this window.
    366       GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable,
    367       for example GraphicsContext.
    368       @see CairoSubWidget, CairoTopLevelWidget
    369     */
    370     const GraphicsContext& getGraphicsContext() const noexcept;
    371 
    372    /**
    373       Get the "native" window handle.
    374       Returned value depends on the platform:
    375        - HaikuOS: This is a pointer to a `BView`.
    376        - MacOS: This is a pointer to an `NSView*`.
    377        - Windows: This is a `HWND`.
    378        - Everything else: This is an [X11] `Window`.
    379     */
    380     uintptr_t getNativeWindowHandle() const noexcept;
    381 
    382    /**
    383       Get the scale factor requested for this window.
    384       This is purely informational, and up to developers to choose what to do with it.
    385 
    386       If you do not want to deal with this yourself,
    387       consider using setGeometryConstraints() where you can specify to automatically scale the window contents.
    388       @see setGeometryConstraints
    389     */
    390     double getScaleFactor() const noexcept;
    391 
    392    /**
    393       Grab the keyboard input focus.
    394     */
    395     void focus();
    396 
    397 #ifndef DGL_FILE_BROWSER_DISABLED
    398    /**
    399       Open a file browser dialog with this window as transient parent.
    400       A few options can be specified to setup the dialog.
    401 
    402       If a path is selected, onFileSelected() will be called with the user chosen path.
    403       If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename.
    404 
    405       This function does not block the event loop.
    406     */
    407     bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
    408 #endif
    409 
    410    /**
    411       Request repaint of this window, for the entire area.
    412     */
    413     void repaint() noexcept;
    414 
    415    /**
    416       Request partial repaint of this window, with bounds according to @a rect.
    417     */
    418     void repaint(const Rectangle<uint>& rect) noexcept;
    419 
    420    /**
    421       Render this window's content into a picture file, specified by @a filename.
    422       Window must be visible and on screen.
    423       Written picture format is PPM.
    424     */
    425     void renderToPicture(const char* filename);
    426 
    427    /**
    428       Run this window as a modal, blocking input events from the parent.
    429       Only valid for windows that have been created with another window as parent (as passed in the constructor).
    430       Can optionally block-wait, but such option is only available if the application is running as standalone.
    431     */
    432     void runAsModal(bool blockWait = false);
    433 
    434    /**
    435       Get the geometry constraints set for the Window.
    436       @see setGeometryConstraints
    437     */
    438     Size<uint> getGeometryConstraints(bool& keepAspectRatio);
    439 
    440    /**
    441       Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
    442     */
    443     void setGeometryConstraints(uint minimumWidth,
    444                                 uint minimumHeight,
    445                                 bool keepAspectRatio = false,
    446                                 bool automaticallyScale = false,
    447                                 bool resizeNowIfAutoScaling = true);
    448 
    449    /**
    450       Set the transient parent of the window.
    451 
    452       Set this for transient children like dialogs, to have them properly associated with their parent window.
    453       This should be not be called for embed windows, or after making the window visible.
    454     */
    455     void setTransientParent(uintptr_t transientParentWindowHandle);
    456 
    457    /** DEPRECATED Use isIgnoringKeyRepeat(). */
    458     DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()")
    459     inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
    460 
    461    /** DEPRECATED Use getScaleFactor(). */
    462     DISTRHO_DEPRECATED_BY("getScaleFactor()")
    463     inline double getScaling() const noexcept { return getScaleFactor(); }
    464 
    465    /** DEPRECATED Use runAsModal(bool). */
    466     DISTRHO_DEPRECATED_BY("runAsModal(bool)")
    467     inline void exec(bool blockWait = false) { runAsModal(blockWait); }
    468 
    469 protected:
    470    /**
    471       Get the types available for the data in a clipboard.
    472       Must only be called within the context of onClipboardDataOffer.
    473     */
    474     std::vector<ClipboardDataOffer> getClipboardDataOfferTypes();
    475 
    476    /**
    477       A function called when clipboard has data present, possibly with several datatypes.
    478       While handling this event, the data types can be investigated with getClipboardDataOfferTypes() to decide whether to accept the offer.
    479 
    480       Reimplement and return a non-zero id to accept the clipboard data offer for a particular type.
    481       Applications must ignore any type they do not recognize.
    482 
    483       The default implementation accepts the "text/plain" mimetype.
    484     */
    485     virtual uint32_t onClipboardDataOffer();
    486 
    487    /**
    488       A function called when the window is attempted to be closed.
    489       Returning true closes the window, which is the default behaviour.
    490       Override this method and return false to prevent the window from being closed by the user.
    491 
    492       This method is not used for embed windows, and not even made available in DISTRHO_NAMESPACE::UI.
    493       For embed windows, closing is handled by the host/parent process and we have no control over it.
    494       As such, a close action on embed windows will always succeed and cannot be cancelled.
    495 
    496       NOTE: This currently does not work under macOS.
    497     */
    498     virtual bool onClose();
    499 
    500    /**
    501       A function called when the window gains or loses the keyboard focus.
    502       The default implementation does nothing.
    503     */
    504     virtual void onFocus(bool focus, CrossingMode mode);
    505 
    506    /**
    507       A function called when the window is resized.
    508       If there is a top-level widget associated with this window, its size will be set right after this function.
    509       The default implementation sets up drawing context where necessary.
    510     */
    511     virtual void onReshape(uint width, uint height);
    512 
    513    /**
    514       A function called when scale factor requested for this window changes.
    515       The default implementation does nothing.
    516       WARNING function needs a proper name
    517     */
    518     virtual void onScaleFactorChanged(double scaleFactor);
    519 
    520 #ifndef DGL_FILE_BROWSER_DISABLED
    521    /**
    522       A function called when a path is selected by the user, as triggered by openFileBrowser().
    523       This action happens after the user confirms the action, so the file browser dialog will be closed at this point.
    524       The default implementation does nothing.
    525     */
    526     virtual void onFileSelected(const char* filename);
    527 
    528    /** DEPRECATED Use onFileSelected(). */
    529     DISTRHO_DEPRECATED_BY("onFileSelected(const char*)")
    530     inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); }
    531 #endif
    532 
    533 private:
    534     PrivateData* const pData;
    535     friend class Application;
    536     friend class TopLevelWidget;
    537    #ifdef DISTRHO_NAMESPACE
    538     friend class DISTRHO_NAMESPACE::PluginWindow;
    539    #endif
    540 
    541    /** @internal */
    542     explicit Window(Application& app,
    543                     uintptr_t parentWindowHandle,
    544                     uint width,
    545                     uint height,
    546                     double scaleFactor,
    547                     bool resizable,
    548                     bool usesScheduledRepaints,
    549                     bool usesSizeRequest,
    550                     bool doPostInit);
    551 
    552     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window)
    553 };
    554 
    555 // -----------------------------------------------------------------------
    556 
    557 END_NAMESPACE_DGL
    558 
    559 #endif // DGL_WINDOW_HPP_INCLUDED