JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_Desktop.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29Desktop::Desktop()
30 : mouseSources (new detail::MouseInputSourceList()),
31 masterScaleFactor ((float) getDefaultMasterScale()),
32 nativeDarkModeChangeDetectorImpl (createNativeDarkModeChangeDetectorImpl())
33{
34 displays.reset (new Displays (*this));
35}
36
37Desktop::~Desktop()
38{
39 setScreenSaverEnabled (true);
40 animator.cancelAllAnimations (false);
41
42 jassert (instance == this);
43 instance = nullptr;
44
45 // doh! If you don't delete all your windows before exiting, you're going to
46 // be leaking memory!
47 jassert (desktopComponents.size() == 0);
48}
49
50Desktop& JUCE_CALLTYPE Desktop::getInstance()
51{
52 if (instance == nullptr)
53 instance = new Desktop();
54
55 return *instance;
56}
57
58Desktop* Desktop::instance = nullptr;
59
60//==============================================================================
61int Desktop::getNumComponents() const noexcept
62{
63 return desktopComponents.size();
64}
65
66Component* Desktop::getComponent (int index) const noexcept
67{
68 return desktopComponents [index];
69}
70
71Component* Desktop::findComponentAt (Point<int> screenPosition) const
72{
74
75 for (int i = desktopComponents.size(); --i >= 0;)
76 {
77 auto* c = desktopComponents.getUnchecked (i);
78
79 if (c->isVisible())
80 {
81 auto relative = c->getLocalPoint (nullptr, screenPosition);
82
83 if (c->contains (relative))
84 return c->getComponentAt (relative);
85 }
86 }
87
88 return nullptr;
89}
90
91//==============================================================================
92LookAndFeel& Desktop::getDefaultLookAndFeel() noexcept
93{
94 if (auto lf = currentLookAndFeel.get())
95 return *lf;
96
97 if (defaultLookAndFeel == nullptr)
98 defaultLookAndFeel.reset (new LookAndFeel_V4());
99
100 auto lf = defaultLookAndFeel.get();
101 jassert (lf != nullptr);
102 currentLookAndFeel = lf;
103 return *lf;
104}
105
106void Desktop::setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel)
107{
109 currentLookAndFeel = newDefaultLookAndFeel;
110
111 for (int i = getNumComponents(); --i >= 0;)
112 if (auto* c = getComponent (i))
113 c->sendLookAndFeelChange();
114}
115
116//==============================================================================
117void Desktop::addDesktopComponent (Component* c)
118{
119 jassert (c != nullptr);
120 jassert (! desktopComponents.contains (c));
121 desktopComponents.addIfNotAlreadyThere (c);
122}
123
124void Desktop::removeDesktopComponent (Component* c)
125{
126 desktopComponents.removeFirstMatchingValue (c);
127}
128
129void Desktop::componentBroughtToFront (Component* c)
130{
131 auto index = desktopComponents.indexOf (c);
132 jassert (index >= 0);
133
134 if (index >= 0)
135 {
136 int newIndex = -1;
137
138 if (! c->isAlwaysOnTop())
139 {
140 newIndex = desktopComponents.size();
141
142 while (newIndex > 0 && desktopComponents.getUnchecked (newIndex - 1)->isAlwaysOnTop())
143 --newIndex;
144
145 --newIndex;
146 }
147
148 desktopComponents.move (index, newIndex);
149 }
150}
151
152//==============================================================================
153Point<int> Desktop::getMousePosition()
154{
155 return getMousePositionFloat().roundToInt();
156}
157
158Point<float> Desktop::getMousePositionFloat()
159{
160 return getInstance().getMainMouseSource().getScreenPosition();
161}
162
163void Desktop::setMousePosition (Point<int> newPosition)
164{
165 getInstance().getMainMouseSource().setScreenPosition (newPosition.toFloat());
166}
167
168Point<int> Desktop::getLastMouseDownPosition()
169{
170 return getInstance().getMainMouseSource().getLastMouseDownPosition().roundToInt();
171}
172
173int Desktop::getMouseButtonClickCounter() const noexcept { return mouseClickCounter; }
174int Desktop::getMouseWheelMoveCounter() const noexcept { return mouseWheelCounter; }
175
176void Desktop::incrementMouseClickCounter() noexcept { ++mouseClickCounter; }
177void Desktop::incrementMouseWheelCounter() noexcept { ++mouseWheelCounter; }
178
179const Array<MouseInputSource>& Desktop::getMouseSources() const noexcept { return mouseSources->sourceArray; }
180int Desktop::getNumMouseSources() const noexcept { return mouseSources->sources.size(); }
181int Desktop::getNumDraggingMouseSources() const noexcept { return mouseSources->getNumDraggingMouseSources(); }
182MouseInputSource* Desktop::getMouseSource (int index) const noexcept { return mouseSources->getMouseSource (index); }
183MouseInputSource* Desktop::getDraggingMouseSource (int index) const noexcept { return mouseSources->getDraggingMouseSource (index); }
184MouseInputSource Desktop::getMainMouseSource() const noexcept { return MouseInputSource (mouseSources->sources.getUnchecked (0)); }
185void Desktop::beginDragAutoRepeat (int interval) { mouseSources->beginDragAutoRepeat (interval); }
186
187//==============================================================================
188void Desktop::addFocusChangeListener (FocusChangeListener* l) { focusListeners.add (l); }
189void Desktop::removeFocusChangeListener (FocusChangeListener* l) { focusListeners.remove (l); }
190void Desktop::triggerFocusCallback() { triggerAsyncUpdate(); }
191
192void Desktop::updateFocusOutline()
193{
194 if (auto* currentFocus = Component::getCurrentlyFocusedComponent())
195 {
196 if (currentFocus->hasFocusOutline())
197 {
198 focusOutline = currentFocus->getLookAndFeel().createFocusOutlineForComponent (*currentFocus);
199
200 if (focusOutline != nullptr)
201 focusOutline->setOwner (currentFocus);
202
203 return;
204 }
205 }
206
207 focusOutline = nullptr;
208}
209
210void Desktop::handleAsyncUpdate()
211{
212 // The component may be deleted during this operation, but we'll use a SafePointer rather than a
213 // BailOutChecker so that any remaining listeners will still get a callback (with a null pointer).
214 focusListeners.call ([currentFocus = WeakReference<Component> { Component::getCurrentlyFocusedComponent() }] (FocusChangeListener& l)
215 {
216 l.globalFocusChanged (currentFocus.get());
217 });
218
219 updateFocusOutline();
220}
221
222//==============================================================================
223void Desktop::addDarkModeSettingListener (DarkModeSettingListener* l) { darkModeSettingListeners.add (l); }
224void Desktop::removeDarkModeSettingListener (DarkModeSettingListener* l) { darkModeSettingListeners.remove (l); }
225
226void Desktop::darkModeChanged() { darkModeSettingListeners.call ([] (auto& l) { l.darkModeSettingChanged(); }); }
227
228//==============================================================================
229void Desktop::resetTimer()
230{
231 if (mouseListeners.size() == 0)
232 stopTimer();
233 else
234 startTimer (100);
235
236 lastFakeMouseMove = getMousePositionFloat();
237}
238
239ListenerList<MouseListener>& Desktop::getMouseListeners()
240{
241 resetTimer();
242 return mouseListeners;
243}
244
245void Desktop::addGlobalMouseListener (MouseListener* listener)
246{
248 mouseListeners.add (listener);
249 resetTimer();
250}
251
252void Desktop::removeGlobalMouseListener (MouseListener* listener)
253{
255 mouseListeners.remove (listener);
256 resetTimer();
257}
258
259void Desktop::timerCallback()
260{
261 if (lastFakeMouseMove != getMousePositionFloat())
262 sendMouseMove();
263}
264
265void Desktop::sendMouseMove()
266{
267 if (! mouseListeners.isEmpty())
268 {
269 startTimer (20);
270
271 lastFakeMouseMove = getMousePositionFloat();
272
273 if (auto* target = findComponentAt (lastFakeMouseMove.roundToInt()))
274 {
275 Component::BailOutChecker checker (target);
276 auto pos = target->getLocalPoint (nullptr, lastFakeMouseMove);
277 auto now = Time::getCurrentTime();
278
279 const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::currentModifiers, MouseInputSource::defaultPressure,
280 MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
281 MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
282 target, target, now, pos, now, 0, false);
283
284 if (me.mods.isAnyMouseButtonDown())
285 mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseDrag (me); });
286 else
287 mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseMove (me); });
288 }
289 }
290}
291
292//==============================================================================
293void Desktop::setKioskModeComponent (Component* componentToUse, bool allowMenusAndBars)
294{
295 if (kioskModeReentrant)
296 return;
297
298 const ScopedValueSetter<bool> setter (kioskModeReentrant, true, false);
299
300 if (kioskModeComponent != componentToUse)
301 {
302 // agh! Don't delete or remove a component from the desktop while it's still the kiosk component!
303 jassert (kioskModeComponent == nullptr || ComponentPeer::getPeerFor (kioskModeComponent) != nullptr);
304
305 if (auto* oldKioskComp = kioskModeComponent)
306 {
307 kioskModeComponent = nullptr; // (to make sure that isKioskMode() returns false when resizing the old one)
308 setKioskComponent (oldKioskComp, false, allowMenusAndBars);
309 oldKioskComp->setBounds (kioskComponentOriginalBounds);
310 }
311
312 kioskModeComponent = componentToUse;
313
314 if (kioskModeComponent != nullptr)
315 {
316 // Only components that are already on the desktop can be put into kiosk mode!
317 jassert (ComponentPeer::getPeerFor (kioskModeComponent) != nullptr);
318
319 kioskComponentOriginalBounds = kioskModeComponent->getBounds();
320 setKioskComponent (kioskModeComponent, true, allowMenusAndBars);
321 }
322 }
323}
324
325//==============================================================================
326void Desktop::setOrientationsEnabled (int newOrientations)
327{
328 if (allowedOrientations != newOrientations)
329 {
330 // Dodgy set of flags being passed here! Make sure you specify at least one permitted orientation.
331 jassert (newOrientations != 0 && (newOrientations & ~allOrientations) == 0);
332
333 allowedOrientations = newOrientations;
334 allowedOrientationsChanged();
335 }
336}
337
338int Desktop::getOrientationsEnabled() const noexcept
339{
340 return allowedOrientations;
341}
342
343bool Desktop::isOrientationEnabled (DisplayOrientation orientation) const noexcept
344{
345 // Make sure you only pass one valid flag in here...
346 jassert (orientation == upright || orientation == upsideDown
347 || orientation == rotatedClockwise || orientation == rotatedAntiClockwise);
348
349 return (allowedOrientations & orientation) != 0;
350}
351
352void Desktop::setGlobalScaleFactor (float newScaleFactor) noexcept
353{
355
356 if (! approximatelyEqual (masterScaleFactor, newScaleFactor))
357 {
358 masterScaleFactor = newScaleFactor;
359 displays->refresh();
360 }
361}
362
363bool Desktop::isHeadless() const noexcept
364{
365 return displays->displays.isEmpty();
366}
367
368} // namespace juce
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
int size() const noexcept
Returns the current number of elements in the array.
Definition juce_Array.h:215
The base class for all JUCE user-interface objects.
Classes can implement this interface and register themselves with the Desktop class to receive callba...
Describes and controls aspects of the computer's desktop.
DisplayOrientation
In a tablet/mobile device which can be turned around, this is used to indicate the orientation.
Classes can implement this interface and register themselves with the Desktop class to receive callba...
The latest JUCE look-and-feel style, as introduced in 2017.
LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses can be used to appl...
Represents a linear source of mouse events from a mouse device or individual finger in a multi-touch ...
A MouseListener can be registered with a component to receive callbacks about mouse events that happe...
A pair of (x, y) coordinates.
Definition juce_Point.h:42
constexpr Point< float > toFloat() const noexcept
Casts this point to a Point<float> object.
Definition juce_Point.h:239
constexpr Point< int > roundToInt() const noexcept
Casts this point to a Point<int> object using roundToInt() to convert the values.
Definition juce_Point.h:245
Helper class providing an RAII-based mechanism for temporarily setting and then re-setting a value.
#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
This macro is used to catch unsafe use of functions which expect to only be called on the message thr...
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_CALLTYPE
This macro defines the C calling convention used as the standard for JUCE calls.
typedef float
JUCE Namespace.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.