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  /** 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
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:949
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:943
Definition: FileBrowserDialogImpl.hpp:33
Definition: Base.hpp:253
Definition: Base.hpp:259
Definition: Window.hpp:95
ScopedGraphicsContext(Window &window)
ScopedGraphicsContext(Window &window, Window &transientParentWindow)