The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
6.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. //==============================================================================
  21. class BluetoothMidiPairingWindowClass : public ObjCClass<NSObject>
  22. {
  23. public:
  24. struct Callbacks
  25. {
  26. std::unique_ptr<ModalComponentManager::Callback> modalExit;
  27. std::function<void()> windowClosed;
  28. };
  29. BluetoothMidiPairingWindowClass() : ObjCClass<NSObject> ("JUCEBluetoothMidiPairingWindowClass_")
  30. {
  31. addIvar<Callbacks*> ("callbacks");
  32. addIvar<CABTLEMIDIWindowController*> ("controller");
  33. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  34. addMethod (@selector (initWithCallbacks:), initWithCallbacks);
  35. addMethod (@selector (show:), show);
  36. addMethod (@selector (receivedWindowWillClose:), receivedWindowWillClose);
  37. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  38. addMethod (@selector (dealloc), dealloc);
  39. registerClass();
  40. }
  41. private:
  42. static CABTLEMIDIWindowController* getController (id self)
  43. {
  44. return getIvar<CABTLEMIDIWindowController*> (self, "controller");
  45. }
  46. static id initWithCallbacks (id self, SEL, Callbacks* cbs)
  47. {
  48. self = sendSuperclassMessage<id> (self, @selector (init));
  49. object_setInstanceVariable (self, "callbacks", cbs);
  50. object_setInstanceVariable (self, "controller", [CABTLEMIDIWindowController new]);
  51. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  52. [[NSNotificationCenter defaultCenter] addObserver: self
  53. selector: @selector (receivedWindowWillClose:)
  54. name: @"NSWindowWillCloseNotification"
  55. object: [getController (self) window]];
  56. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  57. return self;
  58. }
  59. static void dealloc (id self, SEL)
  60. {
  61. [getController (self) release];
  62. sendSuperclassMessage<void> (self, @selector (dealloc));
  63. }
  64. static void show (id self, SEL, Rectangle<int>* bounds)
  65. {
  66. if (bounds != nullptr)
  67. {
  68. auto nsBounds = makeNSRect (*bounds);
  69. auto mainScreenHeight = []
  70. {
  71. if ([[NSScreen screens] count] == 0)
  72. return (CGFloat) 0.0f;
  73. return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
  74. }();
  75. nsBounds.origin.y = mainScreenHeight - (nsBounds.origin.y + nsBounds.size.height);
  76. [getController (self).window setFrame: nsBounds
  77. display: YES];
  78. }
  79. [getController (self) showWindow: nil];
  80. }
  81. static void receivedWindowWillClose (id self, SEL, NSNotification*)
  82. {
  83. [[NSNotificationCenter defaultCenter] removeObserver: self];
  84. auto* cbs = getIvar<Callbacks*> (self, "callbacks");
  85. if (cbs->modalExit != nullptr)
  86. cbs->modalExit->modalStateFinished (0);
  87. cbs->windowClosed();
  88. }
  89. };
  90. class BluetoothMidiSelectorWindowHelper : public DeletedAtShutdown
  91. {
  92. public:
  93. BluetoothMidiSelectorWindowHelper (ModalComponentManager::Callback* exitCallback,
  94. Rectangle<int>* bounds)
  95. {
  96. std::unique_ptr<ModalComponentManager::Callback> exitCB (exitCallback);
  97. static BluetoothMidiPairingWindowClass cls;
  98. window.reset (cls.createInstance());
  99. auto deletionCB = [safeThis = WeakReference<BluetoothMidiSelectorWindowHelper> { this }]
  100. {
  101. if (safeThis != nullptr)
  102. delete safeThis.get();
  103. };
  104. callbacks.reset (new BluetoothMidiPairingWindowClass::Callbacks { std::move (exitCB),
  105. std::move (deletionCB) });
  106. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  107. [window.get() performSelector: @selector (initWithCallbacks:)
  108. withObject: (id) callbacks.get()];
  109. [window.get() performSelector: @selector (show:)
  110. withObject: (id) bounds];
  111. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  112. }
  113. private:
  114. std::unique_ptr<NSObject, NSObjectDeleter> window;
  115. std::unique_ptr<BluetoothMidiPairingWindowClass::Callbacks> callbacks;
  116. JUCE_DECLARE_WEAK_REFERENCEABLE (BluetoothMidiSelectorWindowHelper)
  117. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BluetoothMidiSelectorWindowHelper)
  118. };
  119. //==============================================================================
  120. bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
  121. Rectangle<int>* bounds)
  122. {
  123. if (@available (macOS 10.11, *))
  124. {
  125. new BluetoothMidiSelectorWindowHelper (exitCallback, bounds);
  126. return true;
  127. }
  128. std::unique_ptr<ModalComponentManager::Callback> cb (exitCallback);
  129. // This functionality is unavailable when targetting OSX < 10.11. Instead,
  130. // you should pair Bluetooth MIDI devices using the "Audio MIDI Setup" app
  131. // (located in /Applications/Utilities).
  132. jassertfalse;
  133. return false;
  134. }
  135. bool BluetoothMidiDevicePairingDialogue::isAvailable()
  136. {
  137. if (@available (macOS 10.11, *))
  138. return true;
  139. return false;
  140. }
  141. } // namespace juce