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  /**
54  Constructor for a regular, standalone window.
55  */
56  explicit Window(Application& app);
57 
58  /**
59  Constructor for a modal window, by having another window as its parent.
60  The Application instance must be the same between the 2 windows.
61  */
62  explicit Window(Application& app, Window& parent);
63 
64  /**
65  Constructor for an embed Window without known size,
66  typically used in modules or plugins that run inside another host.
67  */
68  explicit Window(Application& app,
69  uintptr_t parentWindowHandle,
70  double scaleFactor,
71  bool resizable);
72 
73  /**
74  Constructor for an embed Window with known size,
75  typically used in modules or plugins that run inside another host.
76  */
77  explicit Window(Application& app,
78  uintptr_t parentWindowHandle,
79  uint width,
80  uint height,
81  double scaleFactor,
82  bool resizable);
83 
84  /**
85  Destructor.
86  */
87  virtual ~Window();
88 
89  /**
90  Whether this Window is embed into another (usually not DGL-controlled) Window.
91  */
92  bool isEmbed() const noexcept;
93 
94  /**
95  Check if this window is visible / mapped.
96  Invisible windows do not receive events except resize.
97  @see setVisible(bool)
98  */
99  bool isVisible() const noexcept;
100 
101  /**
102  Set windows visible (or not) according to @a visible.
103  Only valid for standalones, embed windows are always visible.
104  @see isVisible(), hide(), show()
105  */
106  void setVisible(bool visible);
107 
108  /**
109  Show window.
110  This is the same as calling setVisible(true).
111  @see isVisible(), setVisible(bool)
112  */
113  void show();
114 
115  /**
116  Hide window.
117  This is the same as calling setVisible(false).
118  @see isVisible(), setVisible(bool)
119  */
120  void hide();
121 
122  /**
123  Hide window and notify application of a window close event.
124  The application event-loop will stop when all windows have been closed.
125  For standalone windows only, has no effect if window is embed.
126  @see isEmbed()
127 
128  @note It is possible to hide the window while not stopping the event-loop.
129  A closed window is always hidden, but the reverse is not always true.
130  */
131  void close();
132 
133  bool isResizable() const noexcept;
134  void setResizable(bool resizable);
135 
136  /**
137  Get width.
138  */
139  uint getWidth() const noexcept;
140 
141  /**
142  Get height.
143  */
144  uint getHeight() const noexcept;
145 
146  /**
147  Get size.
148  */
149  Size<uint> getSize() const noexcept;
150 
151  /**
152  Set width.
153  */
154  void setWidth(uint width);
155 
156  /**
157  Set height.
158  */
159  void setHeight(uint height);
160 
161  /**
162  Set size using @a width and @a height values.
163  */
164  void setSize(uint width, uint height);
165 
166  /**
167  Set size.
168  */
169  void setSize(const Size<uint>& size);
170 
171  /**
172  Get the title of the window previously set with setTitle().
173  */
174  const char* getTitle() const noexcept;
175 
176  /**
177  Set the title of the window, typically displayed in the title bar or in window switchers.
178 
179  This only makes sense for non-embedded windows.
180  */
181  void setTitle(const char* title);
182 
183  /**
184  Check if key repeat events are ignored.
185  */
186  bool isIgnoringKeyRepeat() const noexcept;
187 
188  /**
189  Set to ignore (or not) key repeat events according to @a ignore.
190  */
191  void setIgnoringKeyRepeat(bool ignore) noexcept;
192 
193  /**
194  Add a callback function to be triggered on every idle cycle or on a specific timer frequency.
195  You can add more than one, and remove them at anytime with removeIdleCallback().
196  This can be used to perform some action at a regular interval with relatively low frequency.
197 
198  If providing a timer frequency, there are a few things to note:
199  1. There is a platform-specific limit to the number of supported timers, and overhead associated with each,
200  so you should create only a few timers and perform several tasks in one if necessary.
201  2. This timer frequency is not guaranteed to have a resolution better than 10ms
202  (the maximum timer resolution on Windows) and may be rounded up if it is too short.
203  On X11 and MacOS, a resolution of about 1ms can usually be relied on.
204  */
205  bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0);
206 
207  /**
208  Remove an idle callback previously added via addIdleCallback().
209  */
210  bool removeIdleCallback(IdleCallback* callback);
211 
212  /**
213  Get the application associated with this window.
214  */
215  Application& getApp() const noexcept;
216 
217  /**
218  Get the graphics context associated with this window.
219  GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable,
220  for example GraphicsContext.
221  @see CairoSubWidget, CairoTopLevelWidget
222  */
223  const GraphicsContext& getGraphicsContext() const noexcept;
224 
225  /**
226  Get the "native" window handle.
227  Returned value depends on the platform:
228  - HaikuOS: This is a pointer to a `BView`.
229  - MacOS: This is a pointer to an `NSView*`.
230  - Windows: This is a `HWND`.
231  - Everything else: This is an [X11] `Window`.
232  */
233  uintptr_t getNativeWindowHandle() const noexcept;
234 
235  /**
236  Get the scale factor requested for this window.
237  This is purely informational, and up to developers to choose what to do with it.
238 
239  If you do not want to deal with this yourself,
240  consider using setGeometryConstraints() where you can specify to automatically scale the window contents.
241  @see setGeometryConstraints
242  */
243  double getScaleFactor() const noexcept;
244 
245  /**
246  Grab the keyboard input focus.
247  */
248  void focus();
249 
250  /**
251  Request repaint of this window, for the entire area.
252  */
253  void repaint() noexcept;
254 
255  /**
256  Request partial repaint of this window, with bounds according to @a rect.
257  */
258  void repaint(const Rectangle<uint>& rect) noexcept;
259 
260  /**
261  Run this window as a modal, blocking input events from the parent.
262  Only valid for windows that have been created with another window as parent (as passed in the constructor).
263  Can optionally block-wait, but such option is only available if the application is running as standalone.
264  */
265  void runAsModal(bool blockWait = false);
266 
267  /**
268  Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
269  */
270  void setGeometryConstraints(uint minimumWidth,
271  uint minimumHeight,
272  bool keepAspectRatio = false,
273  bool automaticallyScale = false);
274 
275  /*
276  void setTransientWinId(uintptr_t winId);
277  */
278 
279  DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()")
280  inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
281 
282  DISTRHO_DEPRECATED_BY("getScaleFactor()")
283  inline double getScaling() const noexcept { return getScaleFactor(); }
284 
285  DISTRHO_DEPRECATED_BY("runAsModal(bool)")
286  inline void exec(bool blockWait = false) { runAsModal(blockWait); }
287 
288 protected:
289  /**
290  A function called when the window is attempted to be closed.
291  Returning true closes the window, which is the default behaviour.
292  Override this method and return false to prevent the window from being closed by the user.
293  */
294  virtual bool onClose();
295 
296  /**
297  A function called when the window gains or loses the keyboard focus.
298  The default implementation does nothing.
299  */
300  virtual void onFocus(bool focus, CrossingMode mode);
301 
302  /**
303  A function called when the window is resized.
304  If there is a top-level widget associated with this window, its size will be set right after this function.
305  */
306  virtual void onReshape(uint width, uint height);
307 
308 private:
309  struct PrivateData;
310  PrivateData* const pData;
311  friend class Application;
312  friend class TopLevelWidget;
313 
314  DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window);
315 };
316 
317 // -----------------------------------------------------------------------
318 
319 END_NAMESPACE_DGL
320 
321 /* TODO
322  * add focusEvent with CrossingMode arg
323  * add eventcrossing/enter-leave event
324  */
325 
326 #if 0
327 #ifndef DGL_FILE_BROWSER_DISABLED
328  /**
329  File browser options.
330  */
331  struct FileBrowserOptions {
332  const char* startDir;
333  const char* title;
334  uint width;
335  uint height;
336 
337  /**
338  File browser buttons.
339 
340  0 means hidden.
341  1 means visible and unchecked.
342  2 means visible and checked.
343  */
344  struct Buttons {
345  uint listAllFiles;
346  uint showHidden;
347  uint showPlaces;
348 
349  /** Constuctor for default values */
350  Buttons()
351  : listAllFiles(2),
352  showHidden(1),
353  showPlaces(1) {}
354  } buttons;
355 
356  /** Constuctor for default values */
357  FileBrowserOptions()
358  : startDir(nullptr),
359  title(nullptr),
360  width(0),
361  height(0),
362  buttons() {}
363  };
364 #endif // DGL_FILE_BROWSER_DISABLED
365 
366  void addIdleCallback(IdleCallback* const callback);
367  void removeIdleCallback(IdleCallback* const callback);
368 
369 #ifndef DGL_FILE_BROWSER_DISABLED
370  bool openFileBrowser(const FileBrowserOptions& options);
371 #endif
372 
373 protected:
374 #ifndef DGL_FILE_BROWSER_DISABLED
375  virtual void fileBrowserSelected(const char* filename);
376 #endif
377 
378  bool handlePluginKeyboard(const bool press, const uint key);
379  bool handlePluginSpecial(const bool press, const Key key);
380 #endif
381 
382 // -----------------------------------------------------------------------
383 
384 #endif // DGL_WINDOW_HPP_INCLUDED
Window::runAsModal
void runAsModal(bool blockWait=false)
Window::setHeight
void setHeight(uint height)
Window::onFocus
virtual void onFocus(bool focus, CrossingMode mode)
GraphicsContext
Definition: Base.hpp:154
Window::show
void show()
Window::getNativeWindowHandle
uintptr_t getNativeWindowHandle() const noexcept
Window::isVisible
bool isVisible() const noexcept
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::getTitle
const char * getTitle() const noexcept
Window::getScaleFactor
double getScaleFactor() const noexcept
Window::~Window
virtual ~Window()
Size< uint >
Rectangle
Definition: Geometry.hpp:30
Application
Definition: Application.hpp:34
Window::repaint
void repaint() noexcept
Window::getWidth
uint getWidth() const noexcept
Window::onClose
virtual bool onClose()
Window::getGraphicsContext
const GraphicsContext & getGraphicsContext() const noexcept
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::setWidth
void setWidth(uint width)
Window::setSize
void setSize(uint width, uint height)
Window::isEmbed
bool isEmbed() const noexcept
Window::Window
Window(Application &app)
Window::getApp
Application & getApp() const noexcept
Window::removeIdleCallback
bool removeIdleCallback(IdleCallback *callback)
IdleCallback
Definition: Base.hpp:159
Window::getSize
Size< uint > getSize() const noexcept
Window::focus
void focus()
Window::setIgnoringKeyRepeat
void setIgnoringKeyRepeat(bool ignore) noexcept
Window::isIgnoringKeyRepeat
bool isIgnoringKeyRepeat() const noexcept
Window::getHeight
uint getHeight() const noexcept
TopLevelWidget
Definition: TopLevelWidget.hpp:46
Window::close
void close()
Window::hide
void hide()