DISTRHO Plugin Framework
Window.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 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 START_NAMESPACE_DGL
23 
24 class Application;
25 class TopLevelWidget;
26 
27 // -----------------------------------------------------------------------
28 
29 /**
30  DGL Window class.
31 
32  This is the where all OS-related events initially happen, before being propagated to any widgets.
33 
34  A Window MUST have an Application instance tied to it.
35  It is not possible to swap Application instances from within the lifetime of a Window.
36  But it is possible to completely change the Widgets that a Window contains during its lifetime.
37 
38  Typically the event handling functions as following:
39  Application -> Window -> Top-Level-Widget -> SubWidgets
40 
41  Please note that, unlike many other graphical toolkits out there,
42  DGL makes a clear distinction between a Window and a Widget.
43  You cannot directly draw in a Window, you need to create a Widget for that.
44 
45  Also, a Window MUST have a single top-level Widget.
46  The Window will take care of global screen positioning and resizing, everything else is sent for widgets to handle.
47 
48  ...
49  */
50 class Window
51 {
52 public:
53 #ifndef DGL_FILE_BROWSER_DISABLED
54  /**
55  File browser options.
56  @see Window::openFileBrowser
57  */
59  /**
60  File browser button state.
61  This allows to customize the behaviour of the file browse dialog buttons.
62  */
63  enum ButtonState {
64  kButtonInvisible,
65  kButtonVisibleUnchecked,
66  kButtonVisibleChecked,
67  };
68 
69  /** Start directory, uses current working directory if null */
70  const char* startDir;
71  /** File browser dialog window title, uses "FileBrowser" if null */
72  const char* title;
73  /** File browser dialog window width */
74  uint width;
75  /** File browser dialog window height */
76  uint height;
77  // TODO file filter
78 
79  /**
80  File browser buttons.
81  */
82  struct Buttons {
83  /** Whether to list all files vs only those with matching file extension */
85  /** Whether to show hidden files */
87  /** Whether to show list of places (bookmarks) */
89 
90  /** Constructor for default values */
92  : listAllFiles(kButtonVisibleChecked),
93  showHidden(kButtonVisibleUnchecked),
94  showPlaces(kButtonVisibleUnchecked) {}
95  } buttons;
96 
97  /** Constructor for default values */
99  : startDir(nullptr),
100  title(nullptr),
101  width(0),
102  height(0),
103  buttons() {}
104  };
105 #endif // DGL_FILE_BROWSER_DISABLED
106 
107  /**
108  Window graphics context as a scoped struct.
109  This class gives graphics context drawing time to a window's widgets.
110  Typically used for allowing OpenGL drawing operations during a window + widget constructor.
111 
112  Unless you are subclassing the Window or StandaloneWindow classes, you do not need to care.
113  In such cases you will need to use this struct as a way to get a valid OpenGL context.
114  For example in a standalone application:
115  ```
116  int main()
117  {
118  Application app;
119  Window win(app);
120  ScopedPointer<MyCustomTopLevelWidget> widget;
121  {
122  const ScopedGraphicsContext sgc(win);
123  widget = new MyCustomTopLevelWidget(win);
124  }
125  app.exec();
126  return 0;
127  }
128  ```
129 
130  This struct is necessary because we cannot automatically make the window leave the OpenGL context in custom code.
131  We must always cleanly enter and leave the OpenGL context.
132  In order to avoid messing up the global host context, this class is used around widget creation.
133  */
135  {
136  Window& window;
137  public:
138  explicit ScopedGraphicsContext(Window& window);
140  DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext)
141  DISTRHO_PREVENT_HEAP_ALLOCATION
142  };
143 
144  /**
145  Constructor for a regular, standalone window.
146  */
147  explicit Window(Application& app);
148 
149  /**
150  Constructor for a modal window, by having another window as its parent.
151  The Application instance must be the same between the 2 windows.
152  */
153  explicit Window(Application& app, Window& parent);
154 
155  /**
156  Constructor for an embed Window without known size,
157  typically used in modules or plugins that run inside another host.
158  */
159  explicit Window(Application& app,
160  uintptr_t parentWindowHandle,
161  double scaleFactor,
162  bool resizable);
163 
164  /**
165  Constructor for an embed Window with known size,
166  typically used in modules or plugins that run inside another host.
167  */
168  explicit Window(Application& app,
169  uintptr_t parentWindowHandle,
170  uint width,
171  uint height,
172  double scaleFactor,
173  bool resizable);
174 
175  /**
176  Destructor.
177  */
178  virtual ~Window();
179 
180  /**
181  Whether this Window is embed into another (usually not DGL-controlled) Window.
182  */
183  bool isEmbed() const noexcept;
184 
185  /**
186  Check if this window is visible / mapped.
187  Invisible windows do not receive events except resize.
188  @see setVisible(bool)
189  */
190  bool isVisible() const noexcept;
191 
192  /**
193  Set windows visible (or not) according to @a visible.
194  Only valid for standalones, embed windows are always visible.
195  @see isVisible(), hide(), show()
196  */
197  void setVisible(bool visible);
198 
199  /**
200  Show window.
201  This is the same as calling setVisible(true).
202  @see isVisible(), setVisible(bool)
203  */
204  void show();
205 
206  /**
207  Hide window.
208  This is the same as calling setVisible(false).
209  @see isVisible(), setVisible(bool)
210  */
211  void hide();
212 
213  /**
214  Hide window and notify application of a window close event.
215  The application event-loop will stop when all windows have been closed.
216  For standalone windows only, has no effect if window is embed.
217  @see isEmbed()
218 
219  @note It is possible to hide the window while not stopping the event-loop.
220  A closed window is always hidden, but the reverse is not always true.
221  */
222  void close();
223 
224  /**
225  Check if this window is resizable (by the user or window manager).
226  @see setResizable
227  */
228  bool isResizable() const noexcept;
229 
230  /**
231  Set window as resizable (by the user or window manager).
232  It is always possible to resize a window programmatically, which is not the same as the user being allowed to it.
233  @note This function does nothing for plugins, where the resizable state is set via macro.
234  @see DISTRHO_UI_USER_RESIZABLE
235  */
236  void setResizable(bool resizable);
237 
238  /**
239  Get width.
240  */
241  uint getWidth() const noexcept;
242 
243  /**
244  Get height.
245  */
246  uint getHeight() const noexcept;
247 
248  /**
249  Get size.
250  */
251  Size<uint> getSize() const noexcept;
252 
253  /**
254  Set width.
255  */
256  void setWidth(uint width);
257 
258  /**
259  Set height.
260  */
261  void setHeight(uint height);
262 
263  /**
264  Set size using @a width and @a height values.
265  */
266  void setSize(uint width, uint height);
267 
268  /**
269  Set size.
270  */
271  void setSize(const Size<uint>& size);
272 
273  /**
274  Get the title of the window previously set with setTitle().
275  */
276  const char* getTitle() const noexcept;
277 
278  /**
279  Set the title of the window, typically displayed in the title bar or in window switchers.
280 
281  This only makes sense for non-embedded windows.
282  */
283  void setTitle(const char* title);
284 
285  /**
286  Check if key repeat events are ignored.
287  */
288  bool isIgnoringKeyRepeat() const noexcept;
289 
290  /**
291  Set to ignore (or not) key repeat events according to @a ignore.
292  */
293  void setIgnoringKeyRepeat(bool ignore) noexcept;
294 
295  /**
296  Add a callback function to be triggered on every idle cycle or on a specific timer frequency.
297  You can add more than one, and remove them at anytime with removeIdleCallback().
298  This can be used to perform some action at a regular interval with relatively low frequency.
299 
300  If providing a timer frequency, there are a few things to note:
301  1. There is a platform-specific limit to the number of supported timers, and overhead associated with each,
302  so you should create only a few timers and perform several tasks in one if necessary.
303  2. This timer frequency is not guaranteed to have a resolution better than 10ms
304  (the maximum timer resolution on Windows) and may be rounded up if it is too short.
305  On X11 and MacOS, a resolution of about 1ms can usually be relied on.
306  */
307  bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0);
308 
309  /**
310  Remove an idle callback previously added via addIdleCallback().
311  */
312  bool removeIdleCallback(IdleCallback* callback);
313 
314  /**
315  Get the application associated with this window.
316  */
317  Application& getApp() const noexcept;
318 
319  /**
320  Get the graphics context associated with this window.
321  GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable,
322  for example GraphicsContext.
323  @see CairoSubWidget, CairoTopLevelWidget
324  */
325  const GraphicsContext& getGraphicsContext() const noexcept;
326 
327  /**
328  Get the "native" window handle.
329  Returned value depends on the platform:
330  - HaikuOS: This is a pointer to a `BView`.
331  - MacOS: This is a pointer to an `NSView*`.
332  - Windows: This is a `HWND`.
333  - Everything else: This is an [X11] `Window`.
334  */
335  uintptr_t getNativeWindowHandle() const noexcept;
336 
337  /**
338  Get the scale factor requested for this window.
339  This is purely informational, and up to developers to choose what to do with it.
340 
341  If you do not want to deal with this yourself,
342  consider using setGeometryConstraints() where you can specify to automatically scale the window contents.
343  @see setGeometryConstraints
344  */
345  double getScaleFactor() const noexcept;
346 
347  /**
348  Grab the keyboard input focus.
349  */
350  void focus();
351 
352 #ifndef DGL_FILE_BROWSER_DISABLED
353  /**
354  Open a file browser dialog with this window as parent.
355  A few options can be specified to setup the dialog.
356 
357  If a path is selected, onFileSelected() will be called with the user chosen path.
358  If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename.
359 
360  This function does not block the event loop.
361  */
362  bool openFileBrowser(const FileBrowserOptions& options);
363 #endif
364 
365  /**
366  Request repaint of this window, for the entire area.
367  */
368  void repaint() noexcept;
369 
370  /**
371  Request partial repaint of this window, with bounds according to @a rect.
372  */
373  void repaint(const Rectangle<uint>& rect) noexcept;
374 
375  /**
376  Run this window as a modal, blocking input events from the parent.
377  Only valid for windows that have been created with another window as parent (as passed in the constructor).
378  Can optionally block-wait, but such option is only available if the application is running as standalone.
379  */
380  void runAsModal(bool blockWait = false);
381 
382  /**
383  Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
384  */
385  void setGeometryConstraints(uint minimumWidth,
386  uint minimumHeight,
387  bool keepAspectRatio = false,
388  bool automaticallyScale = false);
389 
390  /** DEPRECATED Use isIgnoringKeyRepeat(). */
391  DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()")
392  inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
393 
394  /** DEPRECATED Use getScaleFactor(). */
395  DISTRHO_DEPRECATED_BY("getScaleFactor()")
396  inline double getScaling() const noexcept { return getScaleFactor(); }
397 
398  /** DEPRECATED Use runAsModal(bool). */
399  DISTRHO_DEPRECATED_BY("runAsModal(bool)")
400  inline void exec(bool blockWait = false) { runAsModal(blockWait); }
401 
402 protected:
403  /**
404  A function called when the window is attempted to be closed.
405  Returning true closes the window, which is the default behaviour.
406  Override this method and return false to prevent the window from being closed by the user.
407 
408  This method is not used for embed windows, and not even made available in DISTRHO_NAMESPACE::UI.
409  For embed windows, closing is handled by the host/parent process and we have no control over it.
410  As such, a close action on embed windows will always succeed and cannot be cancelled.
411  */
412  virtual bool onClose();
413 
414  /**
415  A function called when the window gains or loses the keyboard focus.
416  The default implementation does nothing.
417  */
418  virtual void onFocus(bool focus, CrossingMode mode);
419 
420  /**
421  A function called when the window is resized.
422  If there is a top-level widget associated with this window, its size will be set right after this function.
423  The default implementation sets up drawing context where necessary.
424  */
425  virtual void onReshape(uint width, uint height);
426 
427  /**
428  A function called when scale factor requested for this window changes.
429  The default implementation does nothing.
430  WARNING function needs a proper name
431  */
432  virtual void onScaleFactorChanged(double scaleFactor);
433 
434 #ifndef DGL_FILE_BROWSER_DISABLED
435  /**
436  A function called when a path is selected by the user, as triggered by openFileBrowser().
437  This action happens after the user confirms the action, so the file browser dialog will be closed at this point.
438  The default implementation does nothing.
439  */
440  virtual void onFileSelected(const char* filename);
441 
442  /** DEPRECATED Use onFileSelected(). */
443  DISTRHO_DEPRECATED_BY("onFileSelected(const char*)")
444  inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); }
445 #endif
446 
447 private:
448  struct PrivateData;
449  PrivateData* const pData;
450  friend class Application;
451  friend class PluginWindow;
452  friend class TopLevelWidget;
453 
454  DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window);
455 };
456 
457 // -----------------------------------------------------------------------
458 
459 END_NAMESPACE_DGL
460 
461 #endif // DGL_WINDOW_HPP_INCLUDED
Window::runAsModal
void runAsModal(bool blockWait=false)
Window::isResizable
bool isResizable() const noexcept
Window::FileBrowserOptions::title
const char * title
Definition: Window.hpp:72
Window::fileBrowserSelected
virtual void fileBrowserSelected(const char *filename)
Definition: Window.hpp:444
Window::setHeight
void setHeight(uint height)
Window::onFocus
virtual void onFocus(bool focus, CrossingMode mode)
Window::FileBrowserOptions::startDir
const char * startDir
Definition: Window.hpp:70
Window::FileBrowserOptions::width
uint width
Definition: Window.hpp:74
GraphicsContext
Definition: Base.hpp:154
Window::show
void show()
Window::FileBrowserOptions::Buttons
Definition: Window.hpp:82
Window::getNativeWindowHandle
uintptr_t getNativeWindowHandle() const noexcept
Window::isVisible
bool isVisible() const noexcept
Window::FileBrowserOptions::FileBrowserOptions
FileBrowserOptions()
Definition: Window.hpp:98
Window::setTitle
void setTitle(const char *title)
Window::setGeometryConstraints
void setGeometryConstraints(uint minimumWidth, uint minimumHeight, bool keepAspectRatio=false, bool automaticallyScale=false)
Window
Definition: Window.hpp:50
Window::onScaleFactorChanged
virtual void onScaleFactorChanged(double scaleFactor)
Window::FileBrowserOptions::Buttons::listAllFiles
ButtonState listAllFiles
Definition: Window.hpp:84
Window::getTitle
const char * getTitle() const noexcept
Window::getScaleFactor
double getScaleFactor() const noexcept
Window::~Window
virtual ~Window()
Size
Definition: Geometry.hpp:132
Rectangle
Definition: Geometry.hpp:30
Application
Definition: Application.hpp:36
Window::repaint
void repaint() noexcept
Window::getWidth
uint getWidth() const noexcept
Window::onClose
virtual bool onClose()
Window::getGraphicsContext
const GraphicsContext & getGraphicsContext() const noexcept
Window::FileBrowserOptions::height
uint height
Definition: Window.hpp:76
Window::FileBrowserOptions::Buttons::showHidden
ButtonState showHidden
Definition: Window.hpp:86
Window::addIdleCallback
bool addIdleCallback(IdleCallback *callback, uint timerFrequencyInMs=0)
Window::onReshape
virtual void onReshape(uint width, uint height)
Window::setVisible
void setVisible(bool visible)
Window::getIgnoringKeyRepeat
bool getIgnoringKeyRepeat() const noexcept
Definition: Window.hpp:392
Window::setWidth
void setWidth(uint width)
Window::setSize
void setSize(uint width, uint height)
Window::isEmbed
bool isEmbed() const noexcept
Window::openFileBrowser
bool openFileBrowser(const FileBrowserOptions &options)
Window::onFileSelected
virtual void onFileSelected(const char *filename)
Window::Window
Window(Application &app)
Window::FileBrowserOptions
Definition: Window.hpp:58
Window::getApp
Application & getApp() const noexcept
Window::exec
void exec(bool blockWait=false)
Definition: Window.hpp:400
Window::FileBrowserOptions::ButtonState
ButtonState
Definition: Window.hpp:63
Window::removeIdleCallback
bool removeIdleCallback(IdleCallback *callback)
IdleCallback
Definition: Base.hpp:159
Window::FileBrowserOptions::Buttons::showPlaces
ButtonState showPlaces
Definition: Window.hpp:88
Window::getScaling
double getScaling() const noexcept
Definition: Window.hpp:396
Window::getSize
Size< uint > getSize() const noexcept
Window::focus
void focus()
Window::setResizable
void setResizable(bool resizable)
Window::setIgnoringKeyRepeat
void setIgnoringKeyRepeat(bool ignore) noexcept
Window::isIgnoringKeyRepeat
bool isIgnoringKeyRepeat() const noexcept
Window::getHeight
uint getHeight() const noexcept
Window::FileBrowserOptions::Buttons::Buttons
Buttons()
Definition: Window.hpp:91
Window::ScopedGraphicsContext
Definition: Window.hpp:134
TopLevelWidget
Definition: TopLevelWidget.hpp:46
Window::close
void close()
Window::hide
void hide()