DISTRHO Plugin Framework
Window.hpp
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
30 class PluginWindow;
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  */
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 */
104 
105  /** Early context clearing, useful for standalone windows not created by you. */
106  void done();
107 
108  DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext)
109  DISTRHO_PREVENT_HEAP_ALLOCATION
110 
111  private:
112  Window& window;
113  Window::PrivateData* ppData;
114  bool active;
115  };
116 
117  /**
118  Constructor for a regular, standalone window.
119  */
120  explicit Window(Application& app);
121 
122  /**
123  Constructor for a modal window, by having another window as its transient parent.
124  The Application instance must be the same between the 2 windows.
125  */
126  explicit Window(Application& app, Window& transientParentWindow);
127 
128  /**
129  Constructor for an embed Window without known size,
130  typically used in modules or plugins that run inside another host.
131  */
132  explicit Window(Application& app,
133  uintptr_t parentWindowHandle,
134  double scaleFactor,
135  bool resizable);
136 
137  /**
138  Constructor for an embed Window with known size,
139  typically used in modules or plugins that run inside another host.
140  */
141  explicit Window(Application& app,
142  uintptr_t parentWindowHandle,
143  uint width,
144  uint height,
145  double scaleFactor,
146  bool resizable);
147 
148  /**
149  Destructor.
150  */
151  virtual ~Window();
152 
153  /**
154  Whether this Window is embed into another (usually not DGL-controlled) Window.
155  */
156  bool isEmbed() const noexcept;
157 
158  /**
159  Check if this window is visible / mapped.
160  Invisible windows do not receive events except resize.
161  @see setVisible(bool)
162  */
163  bool isVisible() const noexcept;
164 
165  /**
166  Set window visible (or not) according to @a visible.
167  Only valid for standalones, embed windows are always visible.
168  @see isVisible(), hide(), show()
169  */
170  void setVisible(bool visible);
171 
172  /**
173  Show window.
174  This is the same as calling setVisible(true).
175  @see isVisible(), setVisible(bool)
176  */
177  void show();
178 
179  /**
180  Hide window.
181  This is the same as calling setVisible(false).
182  @see isVisible(), setVisible(bool)
183  */
184  void hide();
185 
186  /**
187  Hide window and notify application of a window close event.
188  The application event-loop will stop when all windows have been closed.
189  For standalone windows only, has no effect if window is embed.
190  @see isEmbed()
191 
192  @note It is possible to hide the window while not stopping the event-loop.
193  A closed window is always hidden, but the reverse is not always true.
194  */
195  void close();
196 
197  /**
198  Check if this window is resizable (by the user or window manager).
199  @see setResizable
200  */
201  bool isResizable() const noexcept;
202 
203  /**
204  Set window as resizable (by the user or window manager).
205  It is always possible to resize a window programmatically, which is not the same as the user being allowed to it.
206  @note This function does nothing for plugins, where the resizable state is set via macro.
207  @see DISTRHO_UI_USER_RESIZABLE
208  */
209  void setResizable(bool resizable);
210 
211  /**
212  Get X offset, typically 0.
213  */
214  int getOffsetX() const noexcept;
215 
216  /**
217  Get Y offset, typically 0.
218  */
219  int getOffsetY() const noexcept;
220 
221  /**
222  Get offset.
223  */
224  Point<int> getOffset() const noexcept;
225 
226  /**
227  Set X offset.
228  */
229  void setOffsetX(int x);
230 
231  /**
232  Set Y offset.
233  */
234  void setOffsetY(int y);
235 
236  /**
237  Set offset using @a x and @a y values.
238  */
239  void setOffset(int x, int y);
240 
241  /**
242  Set offset.
243  */
244  void setOffset(const Point<int>& offset);
245 
246  /**
247  Get width.
248  */
249  uint getWidth() const noexcept;
250 
251  /**
252  Get height.
253  */
254  uint getHeight() const noexcept;
255 
256  /**
257  Get size.
258  */
259  Size<uint> getSize() const noexcept;
260 
261  /**
262  Set width.
263  */
264  void setWidth(uint width);
265 
266  /**
267  Set height.
268  */
269  void setHeight(uint height);
270 
271  /**
272  Set size using @a width and @a height values.
273  */
274  void setSize(uint width, uint height);
275 
276  /**
277  Set size.
278  */
279  void setSize(const Size<uint>& size);
280 
281  /**
282  Get the title of the window previously set with setTitle().
283  */
284  const char* getTitle() const noexcept;
285 
286  /**
287  Set the title of the window, typically displayed in the title bar or in window switchers.
288 
289  This only makes sense for non-embedded windows.
290  */
291  void setTitle(const char* title);
292 
293  /**
294  Check if key repeat events are ignored.
295  */
296  bool isIgnoringKeyRepeat() const noexcept;
297 
298  /**
299  Set to ignore (or not) key repeat events according to @a ignore.
300  */
301  void setIgnoringKeyRepeat(bool ignore) noexcept;
302 
303  /**
304  Get the clipboard contents.
305 
306  This gets the system clipboard contents,
307  which may have been set with setClipboard() or copied from another application.
308 
309  Returns the clipboard contents, or null.
310 
311  @note By default only "text/plain" mimetype is supported and returned.
312  Override onClipboardDataOffer for supporting other types.
313  */
314  const void* getClipboard(size_t& dataSize);
315 
316  /**
317  Set the clipboard contents.
318 
319  This sets the system clipboard contents,
320  which can be retrieved with getClipboard() or pasted into other applications.
321 
322  If using a string, the use of a null terminator is required (and must be part of dataSize).@n
323  The MIME type of the data "text/plain" is assumed if null is used.
324  */
325  bool setClipboard(const char* mimeType, const void* data, size_t dataSize);
326 
327  /**
328  Set the mouse cursor.
329 
330  This changes the system cursor that is displayed when the pointer is inside the window.
331  May fail if setting the cursor is not supported on this system,
332  for example if compiled on X11 without Xcursor support.
333  */
334  bool setCursor(MouseCursor cursor);
335 
336  /**
337  Add a callback function to be triggered on every idle cycle or on a specific timer frequency.
338  You can add more than one, and remove them at anytime with removeIdleCallback().
339  This can be used to perform some action at a regular interval with relatively low frequency.
340 
341  If providing a timer frequency, there are a few things to note:
342  1. There is a platform-specific limit to the number of supported timers, and overhead associated with each,
343  so you should create only a few timers and perform several tasks in one if necessary.
344  2. This timer frequency is not guaranteed to have a resolution better than 10ms
345  (the maximum timer resolution on Windows) and may be rounded up if it is too short.
346  On X11 and MacOS, a resolution of about 1ms can usually be relied on.
347  */
348  bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0);
349 
350  /**
351  Remove an idle callback previously added via addIdleCallback().
352  */
353  bool removeIdleCallback(IdleCallback* callback);
354 
355  /**
356  Get the application associated with this window.
357  */
358  Application& getApp() const noexcept;
359 
360  /**
361  Get the graphics context associated with this window.
362  GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable,
363  for example GraphicsContext.
364  @see CairoSubWidget, CairoTopLevelWidget
365  */
366  const GraphicsContext& getGraphicsContext() const noexcept;
367 
368  /**
369  Get the "native" window handle.
370  Returned value depends on the platform:
371  - HaikuOS: This is a pointer to a `BView`.
372  - MacOS: This is a pointer to an `NSView*`.
373  - Windows: This is a `HWND`.
374  - Everything else: This is an [X11] `Window`.
375  */
376  uintptr_t getNativeWindowHandle() const noexcept;
377 
378  /**
379  Get the scale factor requested for this window.
380  This is purely informational, and up to developers to choose what to do with it.
381 
382  If you do not want to deal with this yourself,
383  consider using setGeometryConstraints() where you can specify to automatically scale the window contents.
384  @see setGeometryConstraints
385  */
386  double getScaleFactor() const noexcept;
387 
388  /**
389  Grab the keyboard input focus.
390  */
391  void focus();
392 
393 #ifndef DGL_FILE_BROWSER_DISABLED
394  /**
395  Open a file browser dialog with this window as transient parent.
396  A few options can be specified to setup the dialog.
397 
398  If a path is selected, onFileSelected() will be called with the user chosen path.
399  If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename.
400 
401  This function does not block the event loop.
402  */
403  bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
404 #endif
405 
406  /**
407  Request repaint of this window, for the entire area.
408  */
409  void repaint() noexcept;
410 
411  /**
412  Request partial repaint of this window, with bounds according to @a rect.
413  */
414  void repaint(const Rectangle<uint>& rect) noexcept;
415 
416  /**
417  Render this window's content into a picture file, specified by @a filename.
418  Window must be visible and on screen.
419  Written picture format is PPM.
420  */
421  void renderToPicture(const char* filename);
422 
423  /**
424  Run this window as a modal, blocking input events from the parent.
425  Only valid for windows that have been created with another window as parent (as passed in the constructor).
426  Can optionally block-wait, but such option is only available if the application is running as standalone.
427  */
428  void runAsModal(bool blockWait = false);
429 
430  /**
431  Get the geometry constraints set for the Window.
432  @see setGeometryConstraints
433  */
434  Size<uint> getGeometryConstraints(bool& keepAspectRatio);
435 
436  /**
437  Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
438  */
439  void setGeometryConstraints(uint minimumWidth,
440  uint minimumHeight,
441  bool keepAspectRatio = false,
442  bool automaticallyScale = false,
443  bool resizeNowIfAutoScaling = true);
444 
445  /**
446  Set the transient parent of the window.
447 
448  Set this for transient children like dialogs, to have them properly associated with their parent window.
449  This should be not be called for embed windows, or after making the window visible.
450  */
451  void setTransientParent(uintptr_t transientParentWindowHandle);
452 
453  /** DEPRECATED Use isIgnoringKeyRepeat(). */
454  DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()")
455  inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
456 
457  /** DEPRECATED Use getScaleFactor(). */
458  DISTRHO_DEPRECATED_BY("getScaleFactor()")
459  inline double getScaling() const noexcept { return getScaleFactor(); }
460 
461  /** DEPRECATED Use runAsModal(bool). */
462  DISTRHO_DEPRECATED_BY("runAsModal(bool)")
463  inline void exec(bool blockWait = false) { runAsModal(blockWait); }
464 
465 protected:
466  /**
467  Get the types available for the data in a clipboard.
468  Must only be called within the context of onClipboardDataOffer.
469  */
470  std::vector<ClipboardDataOffer> getClipboardDataOfferTypes();
471 
472  /**
473  A function called when clipboard has data present, possibly with several datatypes.
474  While handling this event, the data types can be investigated with getClipboardDataOfferTypes() to decide whether to accept the offer.
475 
476  Reimplement and return a non-zero id to accept the clipboard data offer for a particular type.
477  Applications must ignore any type they do not recognize.
478 
479  The default implementation accepts the "text/plain" mimetype.
480  */
481  virtual uint32_t onClipboardDataOffer();
482 
483  /**
484  A function called when the window is attempted to be closed.
485  Returning true closes the window, which is the default behaviour.
486  Override this method and return false to prevent the window from being closed by the user.
487 
488  This method is not used for embed windows, and not even made available in DISTRHO_NAMESPACE::UI.
489  For embed windows, closing is handled by the host/parent process and we have no control over it.
490  As such, a close action on embed windows will always succeed and cannot be cancelled.
491 
492  NOTE: This currently does not work under macOS.
493  */
494  virtual bool onClose();
495 
496  /**
497  A function called when the window gains or loses the keyboard focus.
498  The default implementation does nothing.
499  */
500  virtual void onFocus(bool focus, CrossingMode mode);
501 
502  /**
503  A function called when the window is resized.
504  If there is a top-level widget associated with this window, its size will be set right after this function.
505  The default implementation sets up drawing context where necessary.
506  */
507  virtual void onReshape(uint width, uint height);
508 
509  /**
510  A function called when scale factor requested for this window changes.
511  The default implementation does nothing.
512  WARNING function needs a proper name
513  */
514  virtual void onScaleFactorChanged(double scaleFactor);
515 
516 #ifndef DGL_FILE_BROWSER_DISABLED
517  /**
518  A function called when a path is selected by the user, as triggered by openFileBrowser().
519  This action happens after the user confirms the action, so the file browser dialog will be closed at this point.
520  The default implementation does nothing.
521  */
522  virtual void onFileSelected(const char* filename);
523 
524  /** DEPRECATED Use onFileSelected(). */
525  DISTRHO_DEPRECATED_BY("onFileSelected(const char*)")
526  inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); }
527 #endif
528 
529 private:
530  PrivateData* const pData;
531  friend class Application;
532  friend class TopLevelWidget;
533  #ifdef DISTRHO_NAMESPACE
534  friend class DISTRHO_NAMESPACE::PluginWindow;
535  #endif
536 
537  /** @internal */
538  explicit Window(Application& app,
539  uintptr_t parentWindowHandle,
540  uint width,
541  uint height,
542  double scaleFactor,
543  bool resizable,
544  bool isVST3,
545  bool doPostInit);
546 
547  DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window)
548 };
549 
550 // -----------------------------------------------------------------------
551 
552 END_NAMESPACE_DGL
553 
554 #endif // DGL_WINDOW_HPP_INCLUDED
Definition: Application.hpp:43
Definition: Geometry.hpp:41
Definition: Geometry.hpp:614
Definition: Geometry.hpp:133
Definition: TopLevelWidget.hpp:47
Definition: Window.hpp:63
virtual void onReshape(uint width, uint height)
virtual uint32_t onClipboardDataOffer()
Window(Application &app, uintptr_t parentWindowHandle, double scaleFactor, bool resizable)
Window(Application &app)
virtual void onScaleFactorChanged(double scaleFactor)
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions &options=FileBrowserOptions())
std::vector< ClipboardDataOffer > getClipboardDataOfferTypes()
virtual ~Window()
Window(Application &app, Window &transientParentWindow)
void repaint() noexcept
virtual void onFocus(bool focus, CrossingMode mode)
virtual void onFileSelected(const char *filename)
virtual bool onClose()
Window(Application &app, uintptr_t parentWindowHandle, uint width, uint height, double scaleFactor, bool resizable)
bool isEmbed() const noexcept
#define END_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:834
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:828
Definition: FileBrowserDialogImpl.hpp:33
Definition: Base.hpp:212
Definition: Base.hpp:218
Definition: Window.hpp:95
ScopedGraphicsContext(Window &window)
ScopedGraphicsContext(Window &window, Window &transientParentWindow)